17c478bd9Sstevel@tonic-gate /* 29c57abc8Ssrivijitha dugganapalli * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*89b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved. 57c478bd9Sstevel@tonic-gate */ 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * Copyright (c) 1999,2000 Michael Smith 87c478bd9Sstevel@tonic-gate * Copyright (c) 2000 BSDi 97c478bd9Sstevel@tonic-gate * All rights reserved. 107c478bd9Sstevel@tonic-gate * 117c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 127c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 137c478bd9Sstevel@tonic-gate * are met: 147c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 157c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 167c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 177c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 187c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 217c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 237c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 247c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 257c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 267c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 277c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 287c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 297c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 307c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Copyright (c) 2002 Eric Moore 347c478bd9Sstevel@tonic-gate * Copyright (c) 2002 LSI Logic Corporation 357c478bd9Sstevel@tonic-gate * All rights reserved. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 387c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 397c478bd9Sstevel@tonic-gate * are met: 407c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 417c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 427c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 437c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 447c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 457c478bd9Sstevel@tonic-gate * 3. The party using or redistributing the source code and binary forms 467c478bd9Sstevel@tonic-gate * agrees to the disclaimer below and the terms and conditions set forth 477c478bd9Sstevel@tonic-gate * herein. 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 507c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 517c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 527c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 537c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 547c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 557c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 567c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 577c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 587c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 597c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <sys/int_types.h> 637c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h> 647c478bd9Sstevel@tonic-gate #include <sys/dkbad.h> 657c478bd9Sstevel@tonic-gate #include <sys/dklabel.h> 667c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 677c478bd9Sstevel@tonic-gate #include <sys/cdio.h> 687c478bd9Sstevel@tonic-gate #include <sys/mhd.h> 697c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 707c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 717c478bd9Sstevel@tonic-gate #include <sys/scsi/targets/sddef.h> 727c478bd9Sstevel@tonic-gate #include <sys/debug.h> 737c478bd9Sstevel@tonic-gate #include <sys/pci.h> 747c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 757c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 767c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 777c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 787c478bd9Sstevel@tonic-gate #include <sys/byteorder.h> 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate #include "amrreg.h" 817c478bd9Sstevel@tonic-gate #include "amrvar.h" 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* dynamic debug symbol */ 847c478bd9Sstevel@tonic-gate int amr_debug_var = 0; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate #define AMR_DELAY(cond, count, done_flag) { \ 877c478bd9Sstevel@tonic-gate int local_counter = 0; \ 887c478bd9Sstevel@tonic-gate done_flag = 1; \ 897c478bd9Sstevel@tonic-gate while (!(cond)) { \ 907c478bd9Sstevel@tonic-gate delay(drv_usectohz(100)); \ 917c478bd9Sstevel@tonic-gate if ((local_counter) > count) { \ 927c478bd9Sstevel@tonic-gate done_flag = 0; \ 937c478bd9Sstevel@tonic-gate break; \ 947c478bd9Sstevel@tonic-gate } \ 957c478bd9Sstevel@tonic-gate (local_counter)++; \ 967c478bd9Sstevel@tonic-gate } \ 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define AMR_BUSYWAIT(cond, count, done_flag) { \ 1007c478bd9Sstevel@tonic-gate int local_counter = 0; \ 1017c478bd9Sstevel@tonic-gate done_flag = 1; \ 1027c478bd9Sstevel@tonic-gate while (!(cond)) { \ 1037c478bd9Sstevel@tonic-gate drv_usecwait(100); \ 1047c478bd9Sstevel@tonic-gate if ((local_counter) > count) { \ 1057c478bd9Sstevel@tonic-gate done_flag = 0; \ 1067c478bd9Sstevel@tonic-gate break; \ 1077c478bd9Sstevel@tonic-gate } \ 1087c478bd9Sstevel@tonic-gate (local_counter)++; \ 1097c478bd9Sstevel@tonic-gate } \ 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * driver interfaces 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static uint_t amr_intr(caddr_t arg); 1177c478bd9Sstevel@tonic-gate static void amr_done(struct amr_softs *softs); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 1207c478bd9Sstevel@tonic-gate void *arg, void **result); 1217c478bd9Sstevel@tonic-gate static int amr_attach(dev_info_t *, ddi_attach_cmd_t); 1227c478bd9Sstevel@tonic-gate static int amr_detach(dev_info_t *, ddi_detach_cmd_t); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static int amr_setup_mbox(struct amr_softs *softs); 1257c478bd9Sstevel@tonic-gate static int amr_setup_sg(struct amr_softs *softs); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Command wrappers 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate static int amr_query_controller(struct amr_softs *softs); 1317c478bd9Sstevel@tonic-gate static void *amr_enquiry(struct amr_softs *softs, size_t bufsize, 1327c478bd9Sstevel@tonic-gate uint8_t cmd, uint8_t cmdsub, uint8_t cmdqual); 1337c478bd9Sstevel@tonic-gate static int amr_flush(struct amr_softs *softs); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Command processing. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate static void amr_rw_command(struct amr_softs *softs, 1397c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt, int lun); 1407c478bd9Sstevel@tonic-gate static void amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, 1417c478bd9Sstevel@tonic-gate unsigned int capacity); 1427c478bd9Sstevel@tonic-gate static void amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key); 1437c478bd9Sstevel@tonic-gate static int amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size); 1447c478bd9Sstevel@tonic-gate static void amr_enquiry_unmapcmd(struct amr_command *ac); 145e687df1aSyw161884 static int amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg); 1467c478bd9Sstevel@tonic-gate static void amr_unmapcmd(struct amr_command *ac); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Status monitoring 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate static void amr_periodic(void *data); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Interface-specific shims 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate static int amr_poll_command(struct amr_command *ac); 1577c478bd9Sstevel@tonic-gate static void amr_start_waiting_queue(void *softp); 1587c478bd9Sstevel@tonic-gate static void amr_call_pkt_comp(struct amr_command *head); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * SCSI interface 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate static int amr_setup_tran(dev_info_t *dip, struct amr_softs *softp); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * Function prototypes 1677c478bd9Sstevel@tonic-gate * 1687c478bd9Sstevel@tonic-gate * SCSA functions exported by means of the transport table 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate static int amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 1717c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd); 1727c478bd9Sstevel@tonic-gate static int amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt); 1737c478bd9Sstevel@tonic-gate static int amr_tran_reset(struct scsi_address *ap, int level); 1747c478bd9Sstevel@tonic-gate static int amr_tran_getcap(struct scsi_address *ap, char *cap, int whom); 1757c478bd9Sstevel@tonic-gate static int amr_tran_setcap(struct scsi_address *ap, char *cap, int value, 1767c478bd9Sstevel@tonic-gate int whom); 1777c478bd9Sstevel@tonic-gate static struct scsi_pkt *amr_tran_init_pkt(struct scsi_address *ap, 1787c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 1797c478bd9Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg); 1807c478bd9Sstevel@tonic-gate static void amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); 1817c478bd9Sstevel@tonic-gate static void amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt); 1827c478bd9Sstevel@tonic-gate static void amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static ddi_dma_attr_t buffer_dma_attr = { 1857c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version of this structure */ 1867c478bd9Sstevel@tonic-gate 0, /* lowest usable address */ 1877c478bd9Sstevel@tonic-gate 0xffffffffull, /* highest usable address */ 1887c478bd9Sstevel@tonic-gate 0x00ffffffull, /* maximum DMAable byte count */ 1897c478bd9Sstevel@tonic-gate 4, /* alignment */ 1907c478bd9Sstevel@tonic-gate 1, /* burst sizes */ 1917c478bd9Sstevel@tonic-gate 1, /* minimum transfer */ 1927c478bd9Sstevel@tonic-gate 0xffffffffull, /* maximum transfer */ 1937c478bd9Sstevel@tonic-gate 0xffffffffull, /* maximum segment length */ 1947c478bd9Sstevel@tonic-gate AMR_NSEG, /* maximum number of segments */ 1957c478bd9Sstevel@tonic-gate AMR_BLKSIZE, /* granularity */ 1967c478bd9Sstevel@tonic-gate 0, /* flags (reserved) */ 1977c478bd9Sstevel@tonic-gate }; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate static ddi_dma_attr_t addr_dma_attr = { 2007c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version of this structure */ 2017c478bd9Sstevel@tonic-gate 0, /* lowest usable address */ 2027c478bd9Sstevel@tonic-gate 0xffffffffull, /* highest usable address */ 2037c478bd9Sstevel@tonic-gate 0x7fffffff, /* maximum DMAable byte count */ 2047c478bd9Sstevel@tonic-gate 4, /* alignment */ 2057c478bd9Sstevel@tonic-gate 1, /* burst sizes */ 2067c478bd9Sstevel@tonic-gate 1, /* minimum transfer */ 2077c478bd9Sstevel@tonic-gate 0xffffffffull, /* maximum transfer */ 2087c478bd9Sstevel@tonic-gate 0xffffffffull, /* maximum segment length */ 2097c478bd9Sstevel@tonic-gate 1, /* maximum number of segments */ 2107c478bd9Sstevel@tonic-gate 1, /* granularity */ 2117c478bd9Sstevel@tonic-gate 0, /* flags (reserved) */ 2127c478bd9Sstevel@tonic-gate }; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate static struct dev_ops amr_ops = { 2167c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 2177c478bd9Sstevel@tonic-gate 0, /* refcnt */ 2187c478bd9Sstevel@tonic-gate amr_info, /* info */ 2197c478bd9Sstevel@tonic-gate nulldev, /* identify */ 2207c478bd9Sstevel@tonic-gate nulldev, /* probe */ 2217c478bd9Sstevel@tonic-gate amr_attach, /* attach */ 2227c478bd9Sstevel@tonic-gate amr_detach, /* detach */ 2237c478bd9Sstevel@tonic-gate nodev, /* reset */ 2247c478bd9Sstevel@tonic-gate NULL, /* driver operations */ 2257c478bd9Sstevel@tonic-gate (struct bus_ops *)0, /* bus operations */ 22619397407SSherry Moore 0, /* power */ 22719397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 2287c478bd9Sstevel@tonic-gate }; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2327c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 2337c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. driver here */ 234613b2871SRichard Bean "AMR Driver", /* Name of the module. */ 2357c478bd9Sstevel@tonic-gate &amr_ops, /* Driver ops vector */ 2367c478bd9Sstevel@tonic-gate }; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2397c478bd9Sstevel@tonic-gate MODREV_1, 2407c478bd9Sstevel@tonic-gate &modldrv, 2417c478bd9Sstevel@tonic-gate NULL 2427c478bd9Sstevel@tonic-gate }; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* DMA access attributes */ 2457c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = { 2467c478bd9Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 2477c478bd9Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 2487c478bd9Sstevel@tonic-gate DDI_STRICTORDER_ACC 2497c478bd9Sstevel@tonic-gate }; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate static struct amr_softs *amr_softstatep; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate int 2557c478bd9Sstevel@tonic-gate _init(void) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate int error; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate error = ddi_soft_state_init((void *)&amr_softstatep, 2607c478bd9Sstevel@tonic-gate sizeof (struct amr_softs), 0); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate if (error != 0) 2637c478bd9Sstevel@tonic-gate goto error_out; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if ((error = scsi_hba_init(&modlinkage)) != 0) { 2667c478bd9Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 2677c478bd9Sstevel@tonic-gate goto error_out; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate error = mod_install(&modlinkage); 2717c478bd9Sstevel@tonic-gate if (error != 0) { 2727c478bd9Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 2737c478bd9Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 2747c478bd9Sstevel@tonic-gate goto error_out; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate return (error); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate error_out: 2807c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "_init failed"); 2817c478bd9Sstevel@tonic-gate return (error); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate int 2857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate int 2917c478bd9Sstevel@tonic-gate _fini(void) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate int error; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) { 2967c478bd9Sstevel@tonic-gate return (error); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 3027c478bd9Sstevel@tonic-gate return (error); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate static int 3077c478bd9Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd) 3087c478bd9Sstevel@tonic-gate { 3097c478bd9Sstevel@tonic-gate struct amr_softs *softs; 3107c478bd9Sstevel@tonic-gate int error; 3117c478bd9Sstevel@tonic-gate uint32_t command, i; 3127c478bd9Sstevel@tonic-gate int instance; 3137c478bd9Sstevel@tonic-gate caddr_t cfgaddr; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dev); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate switch (cmd) { 3187c478bd9Sstevel@tonic-gate case DDI_ATTACH: 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate case DDI_RESUME: 3227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate default: 3257c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * Initialize softs. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS) 3327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3337c478bd9Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 3347c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_SOFT_STATE_SETUP; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate softs->dev_info_p = dev; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p", 3397c478bd9Sstevel@tonic-gate (void *)softs, (void *)&(softs->amr_busyslots))); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate if (pci_config_setup(dev, &(softs->pciconfig_handle)) 3427c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 3437c478bd9Sstevel@tonic-gate goto error_out; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_CONFIG_SETUP; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0, 3487c478bd9Sstevel@tonic-gate &accattr, &(softs->regsmap_handle)); 3497c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 3507c478bd9Sstevel@tonic-gate goto error_out; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_MEM_MAPPED; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * Determine board type. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * Make sure we are going to be able to talk to this board. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate if ((command & PCI_COMM_MAE) == 0) { 3637c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "memory window not available")); 3647c478bd9Sstevel@tonic-gate goto error_out; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* force the busmaster enable bit on */ 3687c478bd9Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) { 3697c478bd9Sstevel@tonic-gate command |= PCI_COMM_ME; 3707c478bd9Sstevel@tonic-gate pci_config_put16(softs->pciconfig_handle, 3717c478bd9Sstevel@tonic-gate PCI_CONF_COMM, command); 3727c478bd9Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, 3737c478bd9Sstevel@tonic-gate PCI_CONF_COMM); 3747c478bd9Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) 3757c478bd9Sstevel@tonic-gate goto error_out; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Allocate and connect our interrupt. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dev, 0) != 0) { 38219397407SSherry Moore AMRDB_PRINT((CE_NOTE, 38319397407SSherry Moore "High level interrupt is not supported!")); 3847c478bd9Sstevel@tonic-gate goto error_out; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dev, 0, &softs->iblock_cookiep) 3887c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 3897c478bd9Sstevel@tonic-gate goto error_out; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER, 3937c478bd9Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3947c478bd9Sstevel@tonic-gate mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER, 3957c478bd9Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3967c478bd9Sstevel@tonic-gate mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER, 3977c478bd9Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3987c478bd9Sstevel@tonic-gate /* sychronize waits for the busy slots via this cv */ 3997c478bd9Sstevel@tonic-gate cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL); 4007c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_KMUTEX_INITED; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * Do bus-independent initialisation, bring controller online. 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate if (amr_setup_mbox(softs) != DDI_SUCCESS) 4067c478bd9Sstevel@tonic-gate goto error_out; 4077c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_MAILBOX_SETUP; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate if (amr_setup_sg(softs) != DDI_SUCCESS) 4107c478bd9Sstevel@tonic-gate goto error_out; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_SG_TABLES_SETUP; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate if (amr_query_controller(softs) != DDI_SUCCESS) 4157c478bd9Sstevel@tonic-gate goto error_out; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * A taskq is created for dispatching the waiting queue processing 4197c478bd9Sstevel@tonic-gate * thread. The threads number equals to the logic drive number and 4207c478bd9Sstevel@tonic-gate * the thread number should be 1 if there is no logic driver is 4217c478bd9Sstevel@tonic-gate * configured for this instance. 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq", 4247c478bd9Sstevel@tonic-gate MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) { 4257c478bd9Sstevel@tonic-gate goto error_out; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_TASKQ_SETUP; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL, 4307c478bd9Sstevel@tonic-gate amr_intr, (caddr_t)softs) != DDI_SUCCESS) { 4317c478bd9Sstevel@tonic-gate goto error_out; 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_INTR_SETUP; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* set up the tran interface */ 4367c478bd9Sstevel@tonic-gate if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) { 4377c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "setup tran failed")); 4387c478bd9Sstevel@tonic-gate goto error_out; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_TRAN_SETUP; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* schedule a thread for periodic check */ 4437c478bd9Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 4447c478bd9Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 4457c478bd9Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 4467c478bd9Sstevel@tonic-gate softs->state |= AMR_STATE_TIMEOUT_ENABLED; 4477c478bd9Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* print firmware information in verbose mode */ 4507c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?MegaRaid %s %s attached.", 4517c478bd9Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 4527c478bd9Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* clear any interrupts */ 4557c478bd9Sstevel@tonic-gate AMR_QCLEAR_INTR(softs); 4567c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate error_out: 4597c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_INTR_SETUP) { 4607c478bd9Sstevel@tonic-gate ddi_remove_intr(dev, 0, softs->iblock_cookiep); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_TASKQ_SETUP) { 4637c478bd9Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_SG_TABLES_SETUP) { 4667c478bd9Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 4677c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 4687c478bd9Sstevel@tonic-gate softs->sg_items[i].sg_handle); 4697c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free( 4707c478bd9Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 4717c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle( 4727c478bd9Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_MAILBOX_SETUP) { 4767c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 4777c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 4787c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_KMUTEX_INITED) { 4817c478bd9Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 4827c478bd9Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 4837c478bd9Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 4847c478bd9Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_MEM_MAPPED) 4877c478bd9Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 4887c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_CONFIG_SETUP) 4897c478bd9Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 4907c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_SOFT_STATE_SETUP) 4917c478bd9Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 4927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * Bring the controller down to a dormant state and detach all child devices. 4977c478bd9Sstevel@tonic-gate * This function is called during detach, system shutdown. 4987c478bd9Sstevel@tonic-gate * 4997c478bd9Sstevel@tonic-gate * Note that we can assume that the bufq on the controller is empty, as we won't 5007c478bd9Sstevel@tonic-gate * allow shutdown if any device is open. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5037c478bd9Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate struct amr_softs *softs; 5067c478bd9Sstevel@tonic-gate int instance; 5077c478bd9Sstevel@tonic-gate uint32_t i, done_flag; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dev); 5107c478bd9Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* flush the controllor */ 5137c478bd9Sstevel@tonic-gate if (amr_flush(softs) != 0) { 5147c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "device shutdown failed")); 5157c478bd9Sstevel@tonic-gate return (EIO); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* release the amr timer */ 5197c478bd9Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 5207c478bd9Sstevel@tonic-gate softs->state &= ~AMR_STATE_TIMEOUT_ENABLED; 5217c478bd9Sstevel@tonic-gate if (softs->timeout_t) { 5227c478bd9Sstevel@tonic-gate (void) untimeout(softs->timeout_t); 5237c478bd9Sstevel@tonic-gate softs->timeout_t = 0; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 5287c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 5297c478bd9Sstevel@tonic-gate softs->sg_items[i].sg_handle); 5307c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free( 5317c478bd9Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 5327c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle( 5337c478bd9Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 5377c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 5387c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* disconnect the interrupt handler */ 5417c478bd9Sstevel@tonic-gate ddi_remove_intr(softs->dev_info_p, 0, softs->iblock_cookiep); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* wait for the completion of current in-progress interruptes */ 5447c478bd9Sstevel@tonic-gate AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag); 5457c478bd9Sstevel@tonic-gate if (!done_flag) { 5467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Suspicious interrupts in-progress."); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate (void) scsi_hba_detach(dev); 5527c478bd9Sstevel@tonic-gate scsi_hba_tran_free(softs->hba_tran); 5537c478bd9Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 5547c478bd9Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 5577c478bd9Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 5587c478bd9Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 5597c478bd9Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* print firmware information in verbose mode */ 5627c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "?MegaRaid %s %s detached.", 5637c478bd9Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 5647c478bd9Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5737c478bd9Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 5747c478bd9Sstevel@tonic-gate void *arg, void **result) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate struct amr_softs *softs; 5777c478bd9Sstevel@tonic-gate int instance; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate switch (infocmd) { 5827c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 5837c478bd9Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 5847c478bd9Sstevel@tonic-gate if (softs != NULL) { 5857c478bd9Sstevel@tonic-gate *result = softs->dev_info_p; 5867c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5877c478bd9Sstevel@tonic-gate } else { 5887c478bd9Sstevel@tonic-gate *result = NULL; 5897c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 5927c478bd9Sstevel@tonic-gate *(int *)result = instance; 5937c478bd9Sstevel@tonic-gate break; 5947c478bd9Sstevel@tonic-gate default: 5957c478bd9Sstevel@tonic-gate break; 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * Take an interrupt, or be poked by other code to look for interrupt-worthy 6027c478bd9Sstevel@tonic-gate * status. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate static uint_t 6057c478bd9Sstevel@tonic-gate amr_intr(caddr_t arg) 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)arg; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate softs->amr_interrupts_counter++; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (AMR_QGET_ODB(softs) != AMR_QODB_READY) { 6127c478bd9Sstevel@tonic-gate softs->amr_interrupts_counter--; 6137c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* collect finished commands, queue anything waiting */ 6177c478bd9Sstevel@tonic-gate amr_done(softs); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate softs->amr_interrupts_counter--; 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * Setup the amr mailbox 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate static int 6297c478bd9Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate uint32_t move; 6327c478bd9Sstevel@tonic-gate size_t mbox_len; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle( 6357c478bd9Sstevel@tonic-gate softs->dev_info_p, 6367c478bd9Sstevel@tonic-gate &addr_dma_attr, 6377c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 6387c478bd9Sstevel@tonic-gate NULL, 6397c478bd9Sstevel@tonic-gate &softs->mbox_dma_handle) != DDI_SUCCESS) { 6407c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox")); 6417c478bd9Sstevel@tonic-gate goto error_out; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc( 6457c478bd9Sstevel@tonic-gate softs->mbox_dma_handle, 6467c478bd9Sstevel@tonic-gate sizeof (struct amr_mailbox) + 16, 6477c478bd9Sstevel@tonic-gate &accattr, 6487c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 6497c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 6507c478bd9Sstevel@tonic-gate NULL, 6517c478bd9Sstevel@tonic-gate (caddr_t *)(&softs->mbox), 6527c478bd9Sstevel@tonic-gate &mbox_len, 6537c478bd9Sstevel@tonic-gate &softs->mbox_acc_handle) != 6547c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox")); 6577c478bd9Sstevel@tonic-gate goto error_out; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 6617c478bd9Sstevel@tonic-gate softs->mbox_dma_handle, 6627c478bd9Sstevel@tonic-gate NULL, 6637c478bd9Sstevel@tonic-gate (caddr_t)softs->mbox, 664e687df1aSyw161884 mbox_len, 6657c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 6667c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 6677c478bd9Sstevel@tonic-gate NULL, 6687c478bd9Sstevel@tonic-gate &softs->mbox_dma_cookie, 6697c478bd9Sstevel@tonic-gate &softs->mbox_dma_cookien) != DDI_DMA_MAPPED) { 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox")); 6727c478bd9Sstevel@tonic-gate goto error_out; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (softs->mbox_dma_cookien != 1) 6767c478bd9Sstevel@tonic-gate goto error_out; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* The phy address of mailbox must be aligned on a 16-byte boundary */ 6797c478bd9Sstevel@tonic-gate move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf); 6807c478bd9Sstevel@tonic-gate softs->mbox_phyaddr = 6817c478bd9Sstevel@tonic-gate (softs->mbox_dma_cookie.dmac_address + move); 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate softs->mailbox = 6847c478bd9Sstevel@tonic-gate (struct amr_mailbox *)(((uintptr_t)softs->mbox) + move); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x", 6877c478bd9Sstevel@tonic-gate softs->mbox_phyaddr, (void *)softs->mailbox, 6887c478bd9Sstevel@tonic-gate softs->mbox, move)); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate error_out: 6937c478bd9Sstevel@tonic-gate if (softs->mbox_dma_cookien) 6947c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 6957c478bd9Sstevel@tonic-gate if (softs->mbox_acc_handle) { 6967c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free(&(softs->mbox_acc_handle)); 6977c478bd9Sstevel@tonic-gate softs->mbox_acc_handle = NULL; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate if (softs->mbox_dma_handle) { 7007c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 7017c478bd9Sstevel@tonic-gate softs->mbox_dma_handle = NULL; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * Perform a periodic check of the controller status 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate static void 7117c478bd9Sstevel@tonic-gate amr_periodic(void *data) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate uint32_t i; 7147c478bd9Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)data; 7157c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt; 7167c478bd9Sstevel@tonic-gate register struct amr_command *ac; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 7197c478bd9Sstevel@tonic-gate if (softs->busycmd[i] == NULL) 7207c478bd9Sstevel@tonic-gate continue; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate if (softs->busycmd[i] == NULL) { 7257c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7267c478bd9Sstevel@tonic-gate continue; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate pkt = softs->busycmd[i]->pkt; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate if ((pkt->pkt_time != 0) && 7327c478bd9Sstevel@tonic-gate (ddi_get_time() - 7337c478bd9Sstevel@tonic-gate softs->busycmd[i]->ac_timestamp > 7347c478bd9Sstevel@tonic-gate pkt->pkt_time)) { 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 737e687df1aSyw161884 "!timed out packet detected,\ 7387c478bd9Sstevel@tonic-gate sc = %p, pkt = %p, index = %d, ac = %p", 7397c478bd9Sstevel@tonic-gate (void *)softs, 7407c478bd9Sstevel@tonic-gate (void *)pkt, 7417c478bd9Sstevel@tonic-gate i, 7427c478bd9Sstevel@tonic-gate (void *)softs->busycmd[i]); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate ac = softs->busycmd[i]; 7457c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate /* pull command from the busy index */ 7487c478bd9Sstevel@tonic-gate softs->busycmd[i] = NULL; 7497c478bd9Sstevel@tonic-gate if (softs->amr_busyslots > 0) 7507c478bd9Sstevel@tonic-gate softs->amr_busyslots--; 7517c478bd9Sstevel@tonic-gate if (softs->amr_busyslots == 0) 7527c478bd9Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate pkt = ac->pkt; 7577c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 7587c478bd9Sstevel@tonic-gate pkt->pkt_statistics |= STAT_TIMEOUT; 7597c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_TIMEOUT; 7609c57abc8Ssrivijitha dugganapalli if (!(pkt->pkt_flags & FLAG_NOINTR)) { 7617c478bd9Sstevel@tonic-gate /* call pkt callback */ 7629c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate } else { 7667c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* restart the amr timer */ 7717c478bd9Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 7727c478bd9Sstevel@tonic-gate if (softs->state & AMR_STATE_TIMEOUT_ENABLED) 7737c478bd9Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 7747c478bd9Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 7757c478bd9Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * Interrogate the controller for the operational parameters we require. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate static int 7827c478bd9Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs) 7837c478bd9Sstevel@tonic-gate { 7847c478bd9Sstevel@tonic-gate struct amr_enquiry3 *aex; 7857c478bd9Sstevel@tonic-gate struct amr_prodinfo *ap; 7867c478bd9Sstevel@tonic-gate struct amr_enquiry *ae; 7877c478bd9Sstevel@tonic-gate uint32_t ldrv; 7887c478bd9Sstevel@tonic-gate int instance; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* 7917c478bd9Sstevel@tonic-gate * If we haven't found the real limit yet, let us have a couple of 7927c478bd9Sstevel@tonic-gate * commands in order to be able to probe. 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate if (softs->maxio == 0) 7957c478bd9Sstevel@tonic-gate softs->maxio = 2; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate instance = ddi_get_instance(softs->dev_info_p); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * Try to issue an ENQUIRY3 command 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG, 8037c478bd9Sstevel@tonic-gate AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) { 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry")); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) { 8087c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 8097c478bd9Sstevel@tonic-gate aex->ae_drivesize[ldrv]; 8107c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 8117c478bd9Sstevel@tonic-gate aex->ae_drivestate[ldrv]; 8127c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 8137c478bd9Sstevel@tonic-gate aex->ae_driveprop[ldrv]; 8147c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8157c478bd9Sstevel@tonic-gate " drive %d: size: %d state %x properties %x\n", 8167c478bd9Sstevel@tonic-gate ldrv, 8177c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 8187c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 8197c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 8207c478bd9Sstevel@tonic-gate 82119397407SSherry Moore if (softs->logic_drive[ldrv].al_state == 82219397407SSherry Moore AMR_LDRV_OFFLINE) 82319397407SSherry Moore cmn_err(CE_NOTE, 82419397407SSherry Moore "!instance %d log-drive %d is offline", 8257c478bd9Sstevel@tonic-gate instance, ldrv); 8267c478bd9Sstevel@tonic-gate else 8277c478bd9Sstevel@tonic-gate softs->amr_nlogdrives++; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate kmem_free(aex, AMR_ENQ_BUFFER_SIZE); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, 8327c478bd9Sstevel@tonic-gate AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) { 8337c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8347c478bd9Sstevel@tonic-gate "Cannot obtain product data from controller")); 8357c478bd9Sstevel@tonic-gate return (EIO); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate softs->maxdrives = AMR_40LD_MAXDRIVES; 8397c478bd9Sstevel@tonic-gate softs->maxchan = ap->ap_nschan; 8407c478bd9Sstevel@tonic-gate softs->maxio = ap->ap_maxio; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver, 8437c478bd9Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 8447c478bd9Sstevel@tonic-gate softs->amr_product_info. 8457c478bd9Sstevel@tonic-gate pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate bcopy(ap->ap_product, softs->amr_product_info.pi_product_name, 8487c478bd9Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 8497c478bd9Sstevel@tonic-gate softs->amr_product_info. 8507c478bd9Sstevel@tonic-gate pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate kmem_free(ap, AMR_ENQ_BUFFER_SIZE); 8537c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio)); 8547c478bd9Sstevel@tonic-gate } else { 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry failed, \ 8577c478bd9Sstevel@tonic-gate so try another way")); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* failed, try the 8LD ENQUIRY commands */ 8607c478bd9Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 8617c478bd9Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0)) 8627c478bd9Sstevel@tonic-gate == NULL) { 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 8657c478bd9Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0)) 8667c478bd9Sstevel@tonic-gate == NULL) { 8677c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8687c478bd9Sstevel@tonic-gate "Cannot obtain configuration data")); 8697c478bd9Sstevel@tonic-gate return (EIO); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate ae->ae_signature = 0; 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* 8757c478bd9Sstevel@tonic-gate * Fetch current state of logical drives. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) { 8787c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 8797c478bd9Sstevel@tonic-gate ae->ae_ldrv.al_size[ldrv]; 8807c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 8817c478bd9Sstevel@tonic-gate ae->ae_ldrv.al_state[ldrv]; 8827c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 8837c478bd9Sstevel@tonic-gate ae->ae_ldrv.al_properties[ldrv]; 8847c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8857c478bd9Sstevel@tonic-gate " ********* drive %d: %d state %x properties %x", 8867c478bd9Sstevel@tonic-gate ldrv, 8877c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 8887c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 8897c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 8907c478bd9Sstevel@tonic-gate 89119397407SSherry Moore if (softs->logic_drive[ldrv].al_state == 89219397407SSherry Moore AMR_LDRV_OFFLINE) 89319397407SSherry Moore cmn_err(CE_NOTE, 89419397407SSherry Moore "!instance %d log-drive %d is offline", 8957c478bd9Sstevel@tonic-gate instance, ldrv); 8967c478bd9Sstevel@tonic-gate else 8977c478bd9Sstevel@tonic-gate softs->amr_nlogdrives++; 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate softs->maxdrives = AMR_8LD_MAXDRIVES; 9017c478bd9Sstevel@tonic-gate softs->maxchan = ae->ae_adapter.aa_channels; 9027c478bd9Sstevel@tonic-gate softs->maxio = ae->ae_adapter.aa_maxio; 9037c478bd9Sstevel@tonic-gate kmem_free(ae, AMR_ENQ_BUFFER_SIZE); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * Mark remaining drives as unused. 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate for (; ldrv < AMR_MAXLD; ldrv++) 9107c478bd9Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * Cap the maximum number of outstanding I/Os. AMI's driver 9147c478bd9Sstevel@tonic-gate * doesn't trust the controller's reported value, and lockups have 9157c478bd9Sstevel@tonic-gate * been seen when we do. 9167c478bd9Sstevel@tonic-gate */ 9177c478bd9Sstevel@tonic-gate softs->maxio = MIN(softs->maxio, AMR_LIMITCMD); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate /* 9237c478bd9Sstevel@tonic-gate * Run a generic enquiry-style command. 9247c478bd9Sstevel@tonic-gate */ 9257c478bd9Sstevel@tonic-gate static void * 9267c478bd9Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd, 9277c478bd9Sstevel@tonic-gate uint8_t cmdsub, uint8_t cmdqual) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate struct amr_command ac; 9307c478bd9Sstevel@tonic-gate void *result; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate result = NULL; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 9357c478bd9Sstevel@tonic-gate ac.ac_softs = softs; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* set command flags */ 9387c478bd9Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate /* build the command proper */ 9417c478bd9Sstevel@tonic-gate ac.mailbox.mb_command = cmd; 9427c478bd9Sstevel@tonic-gate ac.mailbox.mb_cmdsub = cmdsub; 9437c478bd9Sstevel@tonic-gate ac.mailbox.mb_cmdqual = cmdqual; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS) 9467c478bd9Sstevel@tonic-gate return (NULL); 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (amr_poll_command(&ac) || ac.ac_status != 0) { 9497c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll command, goto out")); 9507c478bd9Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 9517c478bd9Sstevel@tonic-gate return (NULL); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* allocate the response structure */ 9557c478bd9Sstevel@tonic-gate result = kmem_zalloc(bufsize, KM_SLEEP); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate bcopy(ac.ac_data, result, bufsize); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 9607c478bd9Sstevel@tonic-gate return (result); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * Flush the controller's internal cache, return status. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate static int 9677c478bd9Sstevel@tonic-gate amr_flush(struct amr_softs *softs) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate struct amr_command ac; 9707c478bd9Sstevel@tonic-gate int error = 0; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 9737c478bd9Sstevel@tonic-gate ac.ac_softs = softs; 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* build the command proper */ 9787c478bd9Sstevel@tonic-gate ac.mailbox.mb_command = AMR_CMD_FLUSH; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* have to poll, as the system may be going down or otherwise damaged */ 9817c478bd9Sstevel@tonic-gate if (error = amr_poll_command(&ac)) { 9827c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll this cmd")); 9837c478bd9Sstevel@tonic-gate return (error); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate return (error); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Take a command, submit it to the controller and wait for it to return. 9917c478bd9Sstevel@tonic-gate * Returns nonzero on error. Can be safely called with interrupts enabled. 9927c478bd9Sstevel@tonic-gate */ 9937c478bd9Sstevel@tonic-gate static int 9947c478bd9Sstevel@tonic-gate amr_poll_command(struct amr_command *ac) 9957c478bd9Sstevel@tonic-gate { 9967c478bd9Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 9977c478bd9Sstevel@tonic-gate volatile uint32_t done_flag; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)", 10007c478bd9Sstevel@tonic-gate (void *)&ac->mailbox, 10017c478bd9Sstevel@tonic-gate (void *)softs->mailbox, 10027c478bd9Sstevel@tonic-gate (uint32_t)AMR_MBOX_CMDSIZE)); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate while (softs->amr_busyslots != 0) 10077c478bd9Sstevel@tonic-gate cv_wait(&softs->cmd_cv, &softs->cmd_mutex); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * For read/write commands, the scatter/gather table should be 10117c478bd9Sstevel@tonic-gate * filled, and the last entry in scatter/gather table will be used. 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate if ((ac->mailbox.mb_command == AMR_CMD_LREAD) || 10147c478bd9Sstevel@tonic-gate (ac->mailbox.mb_command == AMR_CMD_LWRITE)) { 10157c478bd9Sstevel@tonic-gate bcopy(ac->sgtable, 10167c478bd9Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_table, 10177c478bd9Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate (void) ddi_dma_sync( 10207c478bd9Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_handle, 10217c478bd9Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate ac->mailbox.mb_physaddr = 10247c478bd9Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_phyaddr; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE); 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate /* sync the dma memory */ 10307c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 10337c478bd9Sstevel@tonic-gate softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID; 10347c478bd9Sstevel@tonic-gate softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS; 10357c478bd9Sstevel@tonic-gate softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS; 10367c478bd9Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 10377c478bd9Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 10387c478bd9Sstevel@tonic-gate softs->mailbox->mb_busy = 1; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* sync the dma memory */ 10437c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS), 10467c478bd9Sstevel@tonic-gate 1000, done_flag); 10477c478bd9Sstevel@tonic-gate if (!done_flag) { 10487c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10497c478bd9Sstevel@tonic-gate return (1); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate ac->ac_status = softs->mailbox->mb_status; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag); 10557c478bd9Sstevel@tonic-gate if (!done_flag) { 10567c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10577c478bd9Sstevel@tonic-gate return (1); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 10617c478bd9Sstevel@tonic-gate softs->mailbox->mb_ack = AMR_POLL_ACK; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* acknowledge that we have the commands */ 10647c478bd9Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag); 10677c478bd9Sstevel@tonic-gate if (!done_flag) { 10687c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10697c478bd9Sstevel@tonic-gate return (1); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10737c478bd9Sstevel@tonic-gate return (ac->ac_status != AMR_STATUS_SUCCESS); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * setup the scatter/gather table 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate static int 10807c478bd9Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs) 10817c478bd9Sstevel@tonic-gate { 10827c478bd9Sstevel@tonic-gate uint32_t i; 10837c478bd9Sstevel@tonic-gate size_t len; 10847c478bd9Sstevel@tonic-gate ddi_dma_cookie_t cookie; 10857c478bd9Sstevel@tonic-gate uint_t cookien; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate softs->sg_max_count = 0; 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate for (i = 0; i < AMR_MAXCMD; i++) { 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* reset the cookien */ 10927c478bd9Sstevel@tonic-gate cookien = 0; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 10957c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle( 10967c478bd9Sstevel@tonic-gate softs->dev_info_p, 10977c478bd9Sstevel@tonic-gate &addr_dma_attr, 10987c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 10997c478bd9Sstevel@tonic-gate NULL, 11007c478bd9Sstevel@tonic-gate &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) { 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 11037c478bd9Sstevel@tonic-gate "Cannot alloc dma handle for s/g table")); 11047c478bd9Sstevel@tonic-gate goto error_out; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle, 11087c478bd9Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG, 11097c478bd9Sstevel@tonic-gate &accattr, 11107c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 11117c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 11127c478bd9Sstevel@tonic-gate (caddr_t *)(&(softs->sg_items[i]).sg_table), 11137c478bd9Sstevel@tonic-gate &len, 11147c478bd9Sstevel@tonic-gate &(softs->sg_items[i]).sg_acc_handle) 11157c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 11187c478bd9Sstevel@tonic-gate "Cannot allocate DMA memory")); 11197c478bd9Sstevel@tonic-gate goto error_out; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 11237c478bd9Sstevel@tonic-gate (softs->sg_items[i]).sg_handle, 11247c478bd9Sstevel@tonic-gate NULL, 11257c478bd9Sstevel@tonic-gate (caddr_t)((softs->sg_items[i]).sg_table), 1126e687df1aSyw161884 len, 11277c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 11287c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 11297c478bd9Sstevel@tonic-gate NULL, 11307c478bd9Sstevel@tonic-gate &cookie, 11317c478bd9Sstevel@tonic-gate &cookien) != DDI_DMA_MAPPED) { 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 11347c478bd9Sstevel@tonic-gate "Cannot bind communication area for s/g table")); 11357c478bd9Sstevel@tonic-gate goto error_out; 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate if (cookien != 1) 11397c478bd9Sstevel@tonic-gate goto error_out; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate softs->sg_items[i].sg_phyaddr = cookie.dmac_address; 11427c478bd9Sstevel@tonic-gate softs->sg_max_count++; 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate error_out: 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * Couldn't allocate/initialize all of the sg table entries. 11507c478bd9Sstevel@tonic-gate * Clean up the partially-initialized entry before returning. 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate if (cookien) { 11537c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate if ((softs->sg_items[i]).sg_acc_handle) { 11567c478bd9Sstevel@tonic-gate (void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle)); 11577c478bd9Sstevel@tonic-gate (softs->sg_items[i]).sg_acc_handle = NULL; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate if ((softs->sg_items[i]).sg_handle) { 11607c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle)); 11617c478bd9Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * At least two sg table entries are needed. One is for regular data 11667c478bd9Sstevel@tonic-gate * I/O commands, the other is for poll I/O commands. 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * Map/unmap (ac)'s data in the controller's addressable space as required. 11737c478bd9Sstevel@tonic-gate * 11747c478bd9Sstevel@tonic-gate * These functions may be safely called multiple times on a given command. 11757c478bd9Sstevel@tonic-gate */ 11767c478bd9Sstevel@tonic-gate static void 11777c478bd9Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep, 11787c478bd9Sstevel@tonic-gate int nsegments) 11797c478bd9Sstevel@tonic-gate { 11807c478bd9Sstevel@tonic-gate struct amr_sgentry *sg; 11817c478bd9Sstevel@tonic-gate uint32_t i, size; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate sg = ac->sgtable; 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate size = 0; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate ac->mailbox.mb_nsgelem = (uint8_t)nsegments; 11887c478bd9Sstevel@tonic-gate for (i = 0; i < nsegments; i++, sg++) { 11897c478bd9Sstevel@tonic-gate sg->sg_addr = buffer_dma_cookiep->dmac_address; 11907c478bd9Sstevel@tonic-gate sg->sg_count = buffer_dma_cookiep->dmac_size; 11917c478bd9Sstevel@tonic-gate size += sg->sg_count; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* 11947c478bd9Sstevel@tonic-gate * There is no next cookie if the end of the current 11957c478bd9Sstevel@tonic-gate * window is reached. Otherwise, the next cookie 11967c478bd9Sstevel@tonic-gate * would be found. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate if ((ac->current_cookie + i + 1) != ac->num_of_cookie) 11997c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(ac->buffer_dma_handle, 12007c478bd9Sstevel@tonic-gate buffer_dma_cookiep); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate ac->transfer_size = size; 12047c478bd9Sstevel@tonic-gate ac->data_transfered += size; 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * map the amr command for enquiry, allocate the DMA resource 12107c478bd9Sstevel@tonic-gate */ 12117c478bd9Sstevel@tonic-gate static int 12127c478bd9Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size) 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 12157c478bd9Sstevel@tonic-gate size_t len; 12167c478bd9Sstevel@tonic-gate uint_t dma_flags; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x", 12197c478bd9Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 12227c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 12237c478bd9Sstevel@tonic-gate } else { 12247c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate /* process the DMA by address bind mode */ 12307c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, 12317c478bd9Sstevel@tonic-gate &addr_dma_attr, DDI_DMA_SLEEP, NULL, 12327c478bd9Sstevel@tonic-gate &ac->buffer_dma_handle) != 12337c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12367c478bd9Sstevel@tonic-gate "Cannot allocate addr DMA tag")); 12377c478bd9Sstevel@tonic-gate goto error_out; 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ac->buffer_dma_handle, 12417c478bd9Sstevel@tonic-gate data_size, 12427c478bd9Sstevel@tonic-gate &accattr, 12437c478bd9Sstevel@tonic-gate dma_flags, 12447c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 12457c478bd9Sstevel@tonic-gate NULL, 12467c478bd9Sstevel@tonic-gate (caddr_t *)&ac->ac_data, 12477c478bd9Sstevel@tonic-gate &len, 12487c478bd9Sstevel@tonic-gate &ac->buffer_acc_handle) != 12497c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12527c478bd9Sstevel@tonic-gate "Cannot allocate DMA memory")); 12537c478bd9Sstevel@tonic-gate goto error_out; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate if ((ddi_dma_addr_bind_handle( 12577c478bd9Sstevel@tonic-gate ac->buffer_dma_handle, 1258e687df1aSyw161884 NULL, ac->ac_data, len, dma_flags, 12597c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie, 12607c478bd9Sstevel@tonic-gate &ac->num_of_cookie)) != DDI_DMA_MAPPED) { 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12637c478bd9Sstevel@tonic-gate "Cannot bind addr for dma")); 12647c478bd9Sstevel@tonic-gate goto error_out; 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate ((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0; 12707c478bd9Sstevel@tonic-gate ac->mailbox.mb_nsgelem = 0; 12717c478bd9Sstevel@tonic-gate ac->mailbox.mb_physaddr = ac->ac_dataphys; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate error_out: 12787c478bd9Sstevel@tonic-gate if (ac->num_of_cookie) 12797c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 12807c478bd9Sstevel@tonic-gate if (ac->buffer_acc_handle) { 12817c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 12827c478bd9Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate if (ac->buffer_dma_handle) { 12857c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 12867c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate /* 12937c478bd9Sstevel@tonic-gate * unmap the amr command for enquiry, free the DMA resource 12947c478bd9Sstevel@tonic-gate */ 12957c478bd9Sstevel@tonic-gate static void 12967c478bd9Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac) 12977c478bd9Sstevel@tonic-gate { 12987c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p", 12997c478bd9Sstevel@tonic-gate (void *)ac)); 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 13027c478bd9Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) { 13037c478bd9Sstevel@tonic-gate if (ac->buffer_dma_handle) 13047c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 13057c478bd9Sstevel@tonic-gate ac->buffer_dma_handle); 13067c478bd9Sstevel@tonic-gate if (ac->buffer_acc_handle) { 13077c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 13087c478bd9Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate if (ac->buffer_dma_handle) { 13117c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle( 13127c478bd9Sstevel@tonic-gate &ac->buffer_dma_handle); 13137c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* 13217c478bd9Sstevel@tonic-gate * map the amr command, allocate the DMA resource 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate static int 1324e687df1aSyw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate uint_t dma_flags; 13277c478bd9Sstevel@tonic-gate off_t off; 13287c478bd9Sstevel@tonic-gate size_t len; 13297c478bd9Sstevel@tonic-gate int error; 1330e687df1aSyw161884 int (*cb)(caddr_t); 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x", 13337c478bd9Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 13367c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 13377c478bd9Sstevel@tonic-gate } else { 13387c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) { 13427c478bd9Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) { 13457c478bd9Sstevel@tonic-gate dma_flags |= DDI_DMA_PARTIAL; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) { 13497c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 13507c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 1353e687df1aSyw161884 cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP; 1354e687df1aSyw161884 13557c478bd9Sstevel@tonic-gate /* if the command involves data at all, and hasn't been mapped */ 13567c478bd9Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_MAPPED)) { 13577c478bd9Sstevel@tonic-gate /* process the DMA by buffer bind mode */ 13587c478bd9Sstevel@tonic-gate error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle, 13597c478bd9Sstevel@tonic-gate ac->ac_buf, 13607c478bd9Sstevel@tonic-gate dma_flags, 1361e687df1aSyw161884 cb, 1362e687df1aSyw161884 arg, 13637c478bd9Sstevel@tonic-gate &ac->buffer_dma_cookie, 13647c478bd9Sstevel@tonic-gate &ac->num_of_cookie); 13657c478bd9Sstevel@tonic-gate switch (error) { 13667c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 13677c478bd9Sstevel@tonic-gate if (ddi_dma_numwin(ac->buffer_dma_handle, 13687c478bd9Sstevel@tonic-gate &ac->num_of_win) == DDI_FAILURE) { 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 13717c478bd9Sstevel@tonic-gate "Cannot get dma num win")); 13727c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 13737c478bd9Sstevel@tonic-gate ac->buffer_dma_handle); 13747c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle( 13757c478bd9Sstevel@tonic-gate &ac->buffer_dma_handle); 13767c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate ac->current_win = 0; 13807c478bd9Sstevel@tonic-gate break; 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate case DDI_DMA_MAPPED: 13837c478bd9Sstevel@tonic-gate ac->num_of_win = 1; 13847c478bd9Sstevel@tonic-gate ac->current_win = 0; 13857c478bd9Sstevel@tonic-gate break; 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate default: 13887c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 13897c478bd9Sstevel@tonic-gate "Cannot bind buf for dma")); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle( 13927c478bd9Sstevel@tonic-gate &ac->buffer_dma_handle); 13937c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate ac->current_cookie = 0; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 14007c478bd9Sstevel@tonic-gate } else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) { 14017c478bd9Sstevel@tonic-gate /* get the next window */ 14027c478bd9Sstevel@tonic-gate ac->current_win++; 14037c478bd9Sstevel@tonic-gate (void) ddi_dma_getwin(ac->buffer_dma_handle, 14047c478bd9Sstevel@tonic-gate ac->current_win, &off, &len, 14057c478bd9Sstevel@tonic-gate &ac->buffer_dma_cookie, 14067c478bd9Sstevel@tonic-gate &ac->num_of_cookie); 14077c478bd9Sstevel@tonic-gate ac->current_cookie = 0; 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) { 14117c478bd9Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG); 14127c478bd9Sstevel@tonic-gate ac->current_cookie += AMR_NSEG; 14137c478bd9Sstevel@tonic-gate } else { 14147c478bd9Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, 14157c478bd9Sstevel@tonic-gate ac->num_of_cookie - ac->current_cookie); 14167c478bd9Sstevel@tonic-gate ac->current_cookie = AMR_LAST_COOKIE_TAG; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate /* 14237c478bd9Sstevel@tonic-gate * unmap the amr command, free the DMA resource 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate static void 14267c478bd9Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac) 14277c478bd9Sstevel@tonic-gate { 14287c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p", 14297c478bd9Sstevel@tonic-gate (void *)ac)); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 14327c478bd9Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && 14337c478bd9Sstevel@tonic-gate ac->ac_buf && ac->buffer_dma_handle) 14347c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate static int 14407c478bd9Sstevel@tonic-gate amr_setup_tran(dev_info_t *dip, struct amr_softs *softp) 14417c478bd9Sstevel@tonic-gate { 14427c478bd9Sstevel@tonic-gate softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* 14457c478bd9Sstevel@tonic-gate * hba_private always points to the amr_softs struct 14467c478bd9Sstevel@tonic-gate */ 14477c478bd9Sstevel@tonic-gate softp->hba_tran->tran_hba_private = softp; 14487c478bd9Sstevel@tonic-gate softp->hba_tran->tran_tgt_init = amr_tran_tgt_init; 14497c478bd9Sstevel@tonic-gate softp->hba_tran->tran_tgt_probe = scsi_hba_probe; 14507c478bd9Sstevel@tonic-gate softp->hba_tran->tran_start = amr_tran_start; 14517c478bd9Sstevel@tonic-gate softp->hba_tran->tran_reset = amr_tran_reset; 14527c478bd9Sstevel@tonic-gate softp->hba_tran->tran_getcap = amr_tran_getcap; 14537c478bd9Sstevel@tonic-gate softp->hba_tran->tran_setcap = amr_tran_setcap; 14547c478bd9Sstevel@tonic-gate softp->hba_tran->tran_init_pkt = amr_tran_init_pkt; 14557c478bd9Sstevel@tonic-gate softp->hba_tran->tran_destroy_pkt = amr_tran_destroy_pkt; 14567c478bd9Sstevel@tonic-gate softp->hba_tran->tran_dmafree = amr_tran_dmafree; 14577c478bd9Sstevel@tonic-gate softp->hba_tran->tran_sync_pkt = amr_tran_sync_pkt; 14587c478bd9Sstevel@tonic-gate softp->hba_tran->tran_abort = NULL; 14597c478bd9Sstevel@tonic-gate softp->hba_tran->tran_tgt_free = NULL; 14607c478bd9Sstevel@tonic-gate softp->hba_tran->tran_quiesce = NULL; 14617c478bd9Sstevel@tonic-gate softp->hba_tran->tran_unquiesce = NULL; 14627c478bd9Sstevel@tonic-gate softp->hba_tran->tran_sd = NULL; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran, 14657c478bd9Sstevel@tonic-gate SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) { 14667c478bd9Sstevel@tonic-gate scsi_hba_tran_free(softp->hba_tran); 14677c478bd9Sstevel@tonic-gate softp->hba_tran = NULL; 14687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14697c478bd9Sstevel@tonic-gate } else { 14707c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14757c478bd9Sstevel@tonic-gate static int 14767c478bd9Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 14777c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd) 14787c478bd9Sstevel@tonic-gate { 14797c478bd9Sstevel@tonic-gate struct amr_softs *softs; 14807c478bd9Sstevel@tonic-gate ushort_t target = sd->sd_address.a_target; 14817c478bd9Sstevel@tonic-gate uchar_t lun = sd->sd_address.a_lun; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate softs = (struct amr_softs *) 14847c478bd9Sstevel@tonic-gate (sd->sd_address.a_hba_tran->tran_hba_private); 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate if ((lun == 0) && (target < AMR_MAXLD)) 14877c478bd9Sstevel@tonic-gate if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE) 14887c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate static int 14947c478bd9Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate struct amr_softs *softs; 14977c478bd9Sstevel@tonic-gate struct buf *bp = NULL; 14987c478bd9Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 14997c478bd9Sstevel@tonic-gate int ret; 15007c478bd9Sstevel@tonic-gate uint32_t capacity; 15017c478bd9Sstevel@tonic-gate struct amr_command *ac; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d", 15047c478bd9Sstevel@tonic-gate cdbp->scc_cmd, ap->a_target, ap->a_lun)); 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 15077c478bd9Sstevel@tonic-gate if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) || 15087c478bd9Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 15097c478bd9Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 15107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "target or lun is not correct!"); 15117c478bd9Sstevel@tonic-gate ret = TRAN_BADPKT; 15127c478bd9Sstevel@tonic-gate return (ret); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 15167c478bd9Sstevel@tonic-gate bp = ac->ac_buf; 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd)); 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate switch (cdbp->scc_cmd) { 15217c478bd9Sstevel@tonic-gate case SCMD_READ: /* read */ 15227c478bd9Sstevel@tonic-gate case SCMD_READ_G1: /* read g1 */ 15237c478bd9Sstevel@tonic-gate case SCMD_READ_BUFFER: /* read buffer */ 15247c478bd9Sstevel@tonic-gate case SCMD_WRITE: /* write */ 15257c478bd9Sstevel@tonic-gate case SCMD_WRITE_G1: /* write g1 */ 15267c478bd9Sstevel@tonic-gate case SCMD_WRITE_BUFFER: /* write buffer */ 15277c478bd9Sstevel@tonic-gate amr_rw_command(softs, pkt, ap->a_target); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_NOINTR) { 15307c478bd9Sstevel@tonic-gate (void) amr_poll_command(ac); 15317c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 15327c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 15337c478bd9Sstevel@tonic-gate | STATE_SENT_CMD 15347c478bd9Sstevel@tonic-gate | STATE_XFERRED_DATA); 15357c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 15367c478bd9Sstevel@tonic-gate pkt->pkt_statistics |= STAT_SYNC; 15377c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 15387c478bd9Sstevel@tonic-gate } else { 15397c478bd9Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 15407c478bd9Sstevel@tonic-gate if (softs->waiting_q_head == NULL) { 15417c478bd9Sstevel@tonic-gate ac->ac_prev = NULL; 15427c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 15437c478bd9Sstevel@tonic-gate softs->waiting_q_head = ac; 15447c478bd9Sstevel@tonic-gate softs->waiting_q_tail = ac; 15457c478bd9Sstevel@tonic-gate } else { 15467c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 15477c478bd9Sstevel@tonic-gate ac->ac_prev = softs->waiting_q_tail; 15487c478bd9Sstevel@tonic-gate softs->waiting_q_tail->ac_next = ac; 15497c478bd9Sstevel@tonic-gate softs->waiting_q_tail = ac; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 15527c478bd9Sstevel@tonic-gate amr_start_waiting_queue((void *)softs); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 15557c478bd9Sstevel@tonic-gate break; 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate case SCMD_INQUIRY: /* inquiry */ 15587c478bd9Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 15597c478bd9Sstevel@tonic-gate struct scsi_inquiry inqp; 15607c478bd9Sstevel@tonic-gate uint8_t *sinq_p = (uint8_t *)&inqp; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate bzero(&inqp, sizeof (struct scsi_inquiry)); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate if (((char *)cdbp)[1] || ((char *)cdbp)[2]) { 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * The EVDP and pagecode is 15677c478bd9Sstevel@tonic-gate * not supported 15687c478bd9Sstevel@tonic-gate */ 15697c478bd9Sstevel@tonic-gate sinq_p[1] = 0xFF; 15707c478bd9Sstevel@tonic-gate sinq_p[2] = 0x0; 15717c478bd9Sstevel@tonic-gate } else { 15727c478bd9Sstevel@tonic-gate inqp.inq_len = AMR_INQ_ADDITIONAL_LEN; 15737c478bd9Sstevel@tonic-gate inqp.inq_ansi = AMR_INQ_ANSI_VER; 15747c478bd9Sstevel@tonic-gate inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT; 1575e687df1aSyw161884 /* Enable Tag Queue */ 1576e687df1aSyw161884 inqp.inq_cmdque = 1; 15777c478bd9Sstevel@tonic-gate bcopy("MegaRaid", inqp.inq_vid, 15787c478bd9Sstevel@tonic-gate sizeof (inqp.inq_vid)); 15797c478bd9Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_product_name, 15807c478bd9Sstevel@tonic-gate inqp.inq_pid, 15817c478bd9Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 15827c478bd9Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_firmware_ver, 15837c478bd9Sstevel@tonic-gate inqp.inq_revision, 15847c478bd9Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 15907c478bd9Sstevel@tonic-gate bp_mapin(bp); 15917c478bd9Sstevel@tonic-gate bcopy(&inqp, bp->b_un.b_addr, 15927c478bd9Sstevel@tonic-gate sizeof (struct scsi_inquiry)); 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 15977c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 15987c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 15997c478bd9Sstevel@tonic-gate | STATE_SENT_CMD); 16007c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16017c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 16027c478bd9Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16039c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 16047c478bd9Sstevel@tonic-gate break; 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate case SCMD_READ_CAPACITY: /* read capacity */ 16077c478bd9Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 16087c478bd9Sstevel@tonic-gate struct scsi_capacity cp; 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 16117c478bd9Sstevel@tonic-gate cp.capacity = BE_32(capacity); 16127c478bd9Sstevel@tonic-gate cp.lbasize = BE_32(512); 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 16177c478bd9Sstevel@tonic-gate bp_mapin(bp); 16187c478bd9Sstevel@tonic-gate bcopy(&cp, bp->b_un.b_addr, 8); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16217c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16227c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 16237c478bd9Sstevel@tonic-gate | STATE_SENT_CMD 16247c478bd9Sstevel@tonic-gate | STATE_XFERRED_DATA); 16257c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16267c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 16277c478bd9Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16289c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 16297c478bd9Sstevel@tonic-gate break; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate case SCMD_MODE_SENSE: /* mode sense */ 16327c478bd9Sstevel@tonic-gate case SCMD_MODE_SENSE_G1: /* mode sense g1 */ 16337c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 16367c478bd9Sstevel@tonic-gate amr_mode_sense(cdbp, bp, capacity); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16397c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16407c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 16417c478bd9Sstevel@tonic-gate | STATE_SENT_CMD 16427c478bd9Sstevel@tonic-gate | STATE_XFERRED_DATA); 16437c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16447c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 16457c478bd9Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16469c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 16477c478bd9Sstevel@tonic-gate break; 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate case SCMD_TEST_UNIT_READY: /* test unit ready */ 16507c478bd9Sstevel@tonic-gate case SCMD_REQUEST_SENSE: /* request sense */ 16517c478bd9Sstevel@tonic-gate case SCMD_FORMAT: /* format */ 16527c478bd9Sstevel@tonic-gate case SCMD_START_STOP: /* start stop */ 16537c478bd9Sstevel@tonic-gate case SCMD_SYNCHRONIZE_CACHE: /* synchronize cache */ 16547c478bd9Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 16557c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 16587c478bd9Sstevel@tonic-gate bp_mapin(bp); 16597c478bd9Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16647c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16657c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 16667c478bd9Sstevel@tonic-gate | STATE_SENT_CMD); 16677c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 16687c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16697c478bd9Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16709c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 16717c478bd9Sstevel@tonic-gate break; 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate default: /* any other commands */ 16747c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 16757c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 16767c478bd9Sstevel@tonic-gate pkt->pkt_state = (STATE_GOT_BUS 16777c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 16787c478bd9Sstevel@tonic-gate | STATE_SENT_CMD 16797c478bd9Sstevel@tonic-gate | STATE_GOT_STATUS 16807c478bd9Sstevel@tonic-gate | STATE_ARQ_DONE); 16817c478bd9Sstevel@tonic-gate ret = TRAN_ACCEPT; 16827c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16837c478bd9Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST); 16847c478bd9Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16859c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 16867c478bd9Sstevel@tonic-gate break; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate return (ret); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate /* 16937c478bd9Sstevel@tonic-gate * tran_reset() will reset the bus/target/adapter to support the fault recovery 16947c478bd9Sstevel@tonic-gate * functionality according to the "level" in interface. However, we got the 16957c478bd9Sstevel@tonic-gate * confirmation from LSI that these HBA cards does not support any commands to 16967c478bd9Sstevel@tonic-gate * reset bus/target/adapter/channel. 16977c478bd9Sstevel@tonic-gate * 16987c478bd9Sstevel@tonic-gate * If the tran_reset() return a FAILURE to the sd, the system will not 16997c478bd9Sstevel@tonic-gate * continue to dump the core. But core dump is an crucial method to analyze 17007c478bd9Sstevel@tonic-gate * problems in panic. Now we adopt a work around solution, that is to return 17017c478bd9Sstevel@tonic-gate * a fake SUCCESS to sd during panic, which will force the system continue 17027c478bd9Sstevel@tonic-gate * to dump core though the core may have problems in some situtation because 17037c478bd9Sstevel@tonic-gate * some on-the-fly commands will continue DMAing data to the memory. 17047c478bd9Sstevel@tonic-gate * In addition, the work around core dump method may not be performed 17057c478bd9Sstevel@tonic-gate * successfully if the panic is caused by the HBA itself. So the work around 17067c478bd9Sstevel@tonic-gate * solution is not a good example for the implementation of tran_reset(), 17077c478bd9Sstevel@tonic-gate * the most reasonable approach should send a reset command to the adapter. 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17107c478bd9Sstevel@tonic-gate static int 17117c478bd9Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level) 17127c478bd9Sstevel@tonic-gate { 17137c478bd9Sstevel@tonic-gate struct amr_softs *softs; 17147c478bd9Sstevel@tonic-gate volatile uint32_t done_flag; 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate if (ddi_in_panic()) { 17177c478bd9Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate /* Acknowledge the card if there are any significant commands */ 17207c478bd9Sstevel@tonic-gate while (softs->amr_busyslots > 0) { 17217c478bd9Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 17227c478bd9Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 17237c478bd9Sstevel@tonic-gate if (!done_flag) { 17247c478bd9Sstevel@tonic-gate /* 17257c478bd9Sstevel@tonic-gate * command not completed, indicate the 17267c478bd9Sstevel@tonic-gate * problem and continue get ac 17277c478bd9Sstevel@tonic-gate */ 17287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 17297c478bd9Sstevel@tonic-gate "AMR command is not completed"); 17307c478bd9Sstevel@tonic-gate return (0); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 17367c478bd9Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 17377c478bd9Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 17387c478bd9Sstevel@tonic-gate if (!done_flag) { 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * command is not completed, return from the 17417c478bd9Sstevel@tonic-gate * current interrupt and wait for the next one 17427c478bd9Sstevel@tonic-gate */ 17437c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 17467c478bd9Sstevel@tonic-gate return (0); 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate softs->amr_busyslots -= softs->mailbox->mb_nstatus; 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /* flush the controllor */ 17537c478bd9Sstevel@tonic-gate (void) amr_flush(softs); 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * If the system is in panic, the tran_reset() will return a 17577c478bd9Sstevel@tonic-gate * fake SUCCESS to sd, then the system would continue dump the 17587c478bd9Sstevel@tonic-gate * core by poll commands. This is a work around for dumping 17597c478bd9Sstevel@tonic-gate * core in panic. 17607c478bd9Sstevel@tonic-gate * 17617c478bd9Sstevel@tonic-gate * Note: Some on-the-fly command will continue DMAing data to 17627c478bd9Sstevel@tonic-gate * the memory when the core is dumping, which may cause 17637c478bd9Sstevel@tonic-gate * some flaws in the dumped core file, so a cmn_err() 17647c478bd9Sstevel@tonic-gate * will be printed out to warn users. However, for most 17657c478bd9Sstevel@tonic-gate * cases, the core file will be fine. 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver " 17687c478bd9Sstevel@tonic-gate "that doesn't support software reset. This " 17697c478bd9Sstevel@tonic-gate "means that memory being used by the HBA for " 17707c478bd9Sstevel@tonic-gate "DMA based reads could have been updated after " 17717c478bd9Sstevel@tonic-gate "we panic'd."); 17727c478bd9Sstevel@tonic-gate return (1); 17737c478bd9Sstevel@tonic-gate } else { 17747c478bd9Sstevel@tonic-gate /* return failure to sd */ 17757c478bd9Sstevel@tonic-gate return (0); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17807c478bd9Sstevel@tonic-gate static int 17817c478bd9Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom) 17827c478bd9Sstevel@tonic-gate { 17837c478bd9Sstevel@tonic-gate struct amr_softs *softs; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* 17867c478bd9Sstevel@tonic-gate * We don't allow inquiring about capabilities for other targets 17877c478bd9Sstevel@tonic-gate */ 17887c478bd9Sstevel@tonic-gate if (cap == NULL || whom == 0) 17897c478bd9Sstevel@tonic-gate return (-1); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private); 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 17947c478bd9Sstevel@tonic-gate case SCSI_CAP_ARQ: 17957c478bd9Sstevel@tonic-gate return (1); 17967c478bd9Sstevel@tonic-gate case SCSI_CAP_GEOMETRY: 17977c478bd9Sstevel@tonic-gate return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS); 17987c478bd9Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 17997c478bd9Sstevel@tonic-gate return (AMR_DEFAULT_SECTORS); 18007c478bd9Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 18017c478bd9Sstevel@tonic-gate /* number of sectors */ 18027c478bd9Sstevel@tonic-gate return (softs->logic_drive[ap->a_target].al_size); 1803e687df1aSyw161884 case SCSI_CAP_UNTAGGED_QING: 1804e687df1aSyw161884 case SCSI_CAP_TAGGED_QING: 1805e687df1aSyw161884 return (1); 18067c478bd9Sstevel@tonic-gate default: 18077c478bd9Sstevel@tonic-gate return (-1); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18127c478bd9Sstevel@tonic-gate static int 18137c478bd9Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value, 18147c478bd9Sstevel@tonic-gate int whom) 18157c478bd9Sstevel@tonic-gate { 18167c478bd9Sstevel@tonic-gate /* 18177c478bd9Sstevel@tonic-gate * We don't allow setting capabilities for other targets 18187c478bd9Sstevel@tonic-gate */ 18197c478bd9Sstevel@tonic-gate if (cap == NULL || whom == 0) { 18207c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 18217c478bd9Sstevel@tonic-gate "Set Cap not supported, string = %s, whom=%d", 18227c478bd9Sstevel@tonic-gate cap, whom)); 18237c478bd9Sstevel@tonic-gate return (-1); 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 18277c478bd9Sstevel@tonic-gate case SCSI_CAP_ARQ: 18287c478bd9Sstevel@tonic-gate return (1); 18297c478bd9Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 18307c478bd9Sstevel@tonic-gate return (1); 18317c478bd9Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 18327c478bd9Sstevel@tonic-gate return (1); 1833e687df1aSyw161884 case SCSI_CAP_UNTAGGED_QING: 1834e687df1aSyw161884 case SCSI_CAP_TAGGED_QING: 1835e687df1aSyw161884 return ((value == 1) ? 1 : 0); 18367c478bd9Sstevel@tonic-gate default: 18377c478bd9Sstevel@tonic-gate return (0); 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate static struct scsi_pkt * 18427c478bd9Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap, 18437c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 18447c478bd9Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg) 18457c478bd9Sstevel@tonic-gate { 18467c478bd9Sstevel@tonic-gate struct amr_softs *softs; 18477c478bd9Sstevel@tonic-gate struct amr_command *ac; 18487c478bd9Sstevel@tonic-gate uint32_t slen; 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)|| 18537c478bd9Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 18547c478bd9Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 18557c478bd9Sstevel@tonic-gate return (NULL); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate if (pkt == NULL) { 18597c478bd9Sstevel@tonic-gate /* force auto request sense */ 18607c478bd9Sstevel@tonic-gate slen = MAX(statuslen, sizeof (struct scsi_arq_status)); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen, 18637c478bd9Sstevel@tonic-gate slen, tgtlen, sizeof (struct amr_command), 18647c478bd9Sstevel@tonic-gate callback, arg); 18657c478bd9Sstevel@tonic-gate if (pkt == NULL) { 18667c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed")); 18677c478bd9Sstevel@tonic-gate return (NULL); 18687c478bd9Sstevel@tonic-gate } 18697c478bd9Sstevel@tonic-gate pkt->pkt_address = *ap; 18707c478bd9Sstevel@tonic-gate pkt->pkt_comp = (void (*)())NULL; 18717c478bd9Sstevel@tonic-gate pkt->pkt_time = 0; 18727c478bd9Sstevel@tonic-gate pkt->pkt_resid = 0; 18737c478bd9Sstevel@tonic-gate pkt->pkt_statistics = 0; 18747c478bd9Sstevel@tonic-gate pkt->pkt_reason = 0; 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 18777c478bd9Sstevel@tonic-gate ac->ac_buf = bp; 18787c478bd9Sstevel@tonic-gate ac->cmdlen = cmdlen; 18797c478bd9Sstevel@tonic-gate ac->ac_softs = softs; 18807c478bd9Sstevel@tonic-gate ac->pkt = pkt; 18817c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 18827c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 18857c478bd9Sstevel@tonic-gate return (pkt); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr, 18897c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 18907c478bd9Sstevel@tonic-gate &ac->buffer_dma_handle) != DDI_SUCCESS) { 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 18937c478bd9Sstevel@tonic-gate "Cannot allocate buffer DMA tag")); 18947c478bd9Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 18957c478bd9Sstevel@tonic-gate return (NULL); 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate } else { 19007c478bd9Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 19017c478bd9Sstevel@tonic-gate return (pkt); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate ASSERT(ac != NULL); 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 19097c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAOUT; 19107c478bd9Sstevel@tonic-gate } else { 19117c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAIN; 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate if (flags & PKT_CONSISTENT) { 19157c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_CONSISTENT; 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate if (flags & PKT_DMA_PARTIAL) { 19197c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 1922e687df1aSyw161884 if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) { 19237c478bd9Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 19247c478bd9Sstevel@tonic-gate return (NULL); 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate pkt->pkt_resid = bp->b_bcount - ac->data_transfered; 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 19307c478bd9Sstevel@tonic-gate "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d", 19317c478bd9Sstevel@tonic-gate (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount, 19327c478bd9Sstevel@tonic-gate ac->data_transfered)); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate ASSERT(pkt->pkt_resid >= 0); 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate return (pkt); 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate static void 19407c478bd9Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 19417c478bd9Sstevel@tonic-gate { 19427c478bd9Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate amr_unmapcmd(ac); 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate if (ac->buffer_dma_handle) { 19477c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 19487c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 19527c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Destroy pkt called")); 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19567c478bd9Sstevel@tonic-gate static void 19577c478bd9Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 19587c478bd9Sstevel@tonic-gate { 19597c478bd9Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate if (ac->buffer_dma_handle) { 19627c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0, 19637c478bd9Sstevel@tonic-gate (ac->ac_flags & AMR_CMD_DATAIN) ? 19647c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19697c478bd9Sstevel@tonic-gate static void 19707c478bd9Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) 19717c478bd9Sstevel@tonic-gate { 19727c478bd9Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_MAPPED) { 19757c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 19767c478bd9Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 19777c478bd9Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 19787c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19847c478bd9Sstevel@tonic-gate static void 19857c478bd9Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target) 19867c478bd9Sstevel@tonic-gate { 19877c478bd9Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19887c478bd9Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 19897c478bd9Sstevel@tonic-gate uint8_t cmd; 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 19927c478bd9Sstevel@tonic-gate cmd = AMR_CMD_LREAD; 19937c478bd9Sstevel@tonic-gate } else { 19947c478bd9Sstevel@tonic-gate cmd = AMR_CMD_LWRITE; 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate ac->mailbox.mb_command = cmd; 19987c478bd9Sstevel@tonic-gate ac->mailbox.mb_blkcount = 19997c478bd9Sstevel@tonic-gate (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE; 20007c478bd9Sstevel@tonic-gate ac->mailbox.mb_lba = (ac->cmdlen == 10) ? 20017c478bd9Sstevel@tonic-gate GETG1ADDR(cdbp) : GETG0ADDR(cdbp); 20027c478bd9Sstevel@tonic-gate ac->mailbox.mb_drive = (uint8_t)target; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate static void 20067c478bd9Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity) 20077c478bd9Sstevel@tonic-gate { 20087c478bd9Sstevel@tonic-gate uchar_t pagecode; 20097c478bd9Sstevel@tonic-gate struct mode_format *page3p; 20107c478bd9Sstevel@tonic-gate struct mode_geometry *page4p; 20117c478bd9Sstevel@tonic-gate struct mode_header *headerp; 20127c478bd9Sstevel@tonic-gate uint32_t ncyl; 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate if (!(bp && bp->b_un.b_addr && bp->b_bcount)) 20157c478bd9Sstevel@tonic-gate return; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 20187c478bd9Sstevel@tonic-gate bp_mapin(bp); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate pagecode = cdbp->cdb_un.sg.scsi[0]; 20217c478bd9Sstevel@tonic-gate switch (pagecode) { 20227c478bd9Sstevel@tonic-gate case SD_MODE_SENSE_PAGE3_CODE: 20237c478bd9Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 20247c478bd9Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate page3p = (struct mode_format *)((caddr_t)headerp + 20277c478bd9Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 20287c478bd9Sstevel@tonic-gate page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE); 20297c478bd9Sstevel@tonic-gate page3p->mode_page.length = BE_8(sizeof (struct mode_format)); 20307c478bd9Sstevel@tonic-gate page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS); 20317c478bd9Sstevel@tonic-gate page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS); 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate return; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate case SD_MODE_SENSE_PAGE4_CODE: 20367c478bd9Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 20377c478bd9Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate page4p = (struct mode_geometry *)((caddr_t)headerp + 20407c478bd9Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 20417c478bd9Sstevel@tonic-gate page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE); 20427c478bd9Sstevel@tonic-gate page4p->mode_page.length = BE_8(sizeof (struct mode_geometry)); 20437c478bd9Sstevel@tonic-gate page4p->heads = BE_8(AMR_DEFAULT_HEADS); 20447c478bd9Sstevel@tonic-gate page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS); 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS); 20477c478bd9Sstevel@tonic-gate page4p->cyl_lb = BE_8(ncyl & 0xff); 20487c478bd9Sstevel@tonic-gate page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff); 20497c478bd9Sstevel@tonic-gate page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff); 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate return; 20527c478bd9Sstevel@tonic-gate default: 20537c478bd9Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 20547c478bd9Sstevel@tonic-gate return; 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate static void 20597c478bd9Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key) 20607c478bd9Sstevel@tonic-gate { 20617c478bd9Sstevel@tonic-gate struct scsi_arq_status *arqstat; 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp); 20647c478bd9Sstevel@tonic-gate arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */ 20657c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_reason = CMD_CMPLT; 20667c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_resid = 0; 20677c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | 20687c478bd9Sstevel@tonic-gate STATE_SENT_CMD | STATE_XFERRED_DATA; 20697c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_statistics = 0; 20707c478bd9Sstevel@tonic-gate arqstat->sts_sensedata.es_valid = 1; 20717c478bd9Sstevel@tonic-gate arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE; 20727c478bd9Sstevel@tonic-gate arqstat->sts_sensedata.es_key = key; 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate static void 20767c478bd9Sstevel@tonic-gate amr_start_waiting_queue(void *softp) 20777c478bd9Sstevel@tonic-gate { 20787c478bd9Sstevel@tonic-gate uint32_t slot; 20797c478bd9Sstevel@tonic-gate struct amr_command *ac; 20807c478bd9Sstevel@tonic-gate volatile uint32_t done_flag; 20817c478bd9Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)softp; 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* only one command allowed at the same time */ 20847c478bd9Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 20857c478bd9Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 20867c478bd9Sstevel@tonic-gate 20877c478bd9Sstevel@tonic-gate while ((ac = softs->waiting_q_head) != NULL) { 20887c478bd9Sstevel@tonic-gate /* 20897c478bd9Sstevel@tonic-gate * Find an available slot, the last slot is 20907c478bd9Sstevel@tonic-gate * occupied by poll I/O command. 20917c478bd9Sstevel@tonic-gate */ 20927c478bd9Sstevel@tonic-gate for (slot = 0; slot < (softs->sg_max_count - 1); slot++) { 20937c478bd9Sstevel@tonic-gate if (softs->busycmd[slot] == NULL) { 20947c478bd9Sstevel@tonic-gate if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) { 20957c478bd9Sstevel@tonic-gate /* 20967c478bd9Sstevel@tonic-gate * only one command allowed at the 20977c478bd9Sstevel@tonic-gate * same time 20987c478bd9Sstevel@tonic-gate */ 20997c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 21007c478bd9Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 21017c478bd9Sstevel@tonic-gate return; 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate ac->ac_timestamp = ddi_get_time(); 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) { 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate softs->busycmd[slot] = ac; 21097c478bd9Sstevel@tonic-gate ac->ac_slot = slot; 21107c478bd9Sstevel@tonic-gate softs->amr_busyslots++; 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate bcopy(ac->sgtable, 21137c478bd9Sstevel@tonic-gate softs->sg_items[slot].sg_table, 211419397407SSherry Moore sizeof (struct amr_sgentry) * 211519397407SSherry Moore AMR_NSEG); 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate (void) ddi_dma_sync( 21187c478bd9Sstevel@tonic-gate softs->sg_items[slot].sg_handle, 21197c478bd9Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate ac->mailbox.mb_physaddr = 21227c478bd9Sstevel@tonic-gate softs->sg_items[slot].sg_phyaddr; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate /* take the cmd from the queue */ 21267c478bd9Sstevel@tonic-gate softs->waiting_q_head = ac->ac_next; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate ac->mailbox.mb_ident = ac->ac_slot + 1; 21297c478bd9Sstevel@tonic-gate ac->mailbox.mb_busy = 1; 21307c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 21317c478bd9Sstevel@tonic-gate ac->ac_prev = NULL; 21327c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_GOT_SLOT; 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 21357c478bd9Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 21367c478bd9Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 21397c478bd9Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 21407c478bd9Sstevel@tonic-gate if (!done_flag) { 21417c478bd9Sstevel@tonic-gate /* 21427c478bd9Sstevel@tonic-gate * command not completed, indicate the 21437c478bd9Sstevel@tonic-gate * problem and continue get ac 21447c478bd9Sstevel@tonic-gate */ 21457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 21467c478bd9Sstevel@tonic-gate "AMR command is not completed"); 21477c478bd9Sstevel@tonic-gate break; 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, 21517c478bd9Sstevel@tonic-gate AMR_MBOX_CMDSIZE); 21527c478bd9Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_BUSY; 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 21557c478bd9Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate AMR_QPUT_IDB(softs, 21587c478bd9Sstevel@tonic-gate softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate /* 21617c478bd9Sstevel@tonic-gate * current ac is submitted 21627c478bd9Sstevel@tonic-gate * so quit 'for-loop' to get next ac 21637c478bd9Sstevel@tonic-gate */ 21647c478bd9Sstevel@tonic-gate break; 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate /* no slot, finish our task */ 21697c478bd9Sstevel@tonic-gate if (slot == softs->maxio) 21707c478bd9Sstevel@tonic-gate break; 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate /* only one command allowed at the same time */ 21747c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 21757c478bd9Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate static void 21797c478bd9Sstevel@tonic-gate amr_done(struct amr_softs *softs) 21807c478bd9Sstevel@tonic-gate { 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate uint32_t i, idx; 21837c478bd9Sstevel@tonic-gate volatile uint32_t done_flag; 21847c478bd9Sstevel@tonic-gate struct amr_mailbox *mbox, mbsave; 21857c478bd9Sstevel@tonic-gate struct amr_command *ac, *head, *tail; 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate head = tail = NULL; 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate AMR_QPUT_ODB(softs, AMR_QODB_READY); 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate /* acknowledge interrupt */ 21927c478bd9Sstevel@tonic-gate (void) AMR_QGET_ODB(softs); 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate if (softs->mailbox->mb_nstatus != 0) { 21977c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 21987c478bd9Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORCPU); 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate /* save mailbox, which contains a list of completed commands */ 22017c478bd9Sstevel@tonic-gate bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox, 22027c478bd9Sstevel@tonic-gate &mbsave, sizeof (mbsave)); 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate mbox = &mbsave; 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 22097c478bd9Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 22107c478bd9Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 22117c478bd9Sstevel@tonic-gate if (!done_flag) { 22127c478bd9Sstevel@tonic-gate /* 22137c478bd9Sstevel@tonic-gate * command is not completed, return from the current 22147c478bd9Sstevel@tonic-gate * interrupt and wait for the next one 22157c478bd9Sstevel@tonic-gate */ 22167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 22197c478bd9Sstevel@tonic-gate return; 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate for (i = 0; i < mbox->mb_nstatus; i++) { 22237c478bd9Sstevel@tonic-gate idx = mbox->mb_completed[i] - 1; 22247c478bd9Sstevel@tonic-gate ac = softs->busycmd[idx]; 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate if (ac != NULL) { 22277c478bd9Sstevel@tonic-gate /* pull the command from the busy index */ 22287c478bd9Sstevel@tonic-gate softs->busycmd[idx] = NULL; 22297c478bd9Sstevel@tonic-gate if (softs->amr_busyslots > 0) 22307c478bd9Sstevel@tonic-gate softs->amr_busyslots--; 22317c478bd9Sstevel@tonic-gate if (softs->amr_busyslots == 0) 22327c478bd9Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 22357c478bd9Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 22367c478bd9Sstevel@tonic-gate ac->ac_status = mbox->mb_status; 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* enqueue here */ 22397c478bd9Sstevel@tonic-gate if (head) { 22407c478bd9Sstevel@tonic-gate tail->ac_next = ac; 22417c478bd9Sstevel@tonic-gate tail = ac; 22427c478bd9Sstevel@tonic-gate tail->ac_next = NULL; 22437c478bd9Sstevel@tonic-gate } else { 22447c478bd9Sstevel@tonic-gate tail = head = ac; 22457c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 22467c478bd9Sstevel@tonic-gate } 22477c478bd9Sstevel@tonic-gate } else { 22487c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 22497c478bd9Sstevel@tonic-gate "ac in mailbox is NULL!")); 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate } else { 22537c478bd9Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!")); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate if (head != NULL) { 22597c478bd9Sstevel@tonic-gate amr_call_pkt_comp(head); 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate /* dispatch a thread to process the pending I/O if there is any */ 22637c478bd9Sstevel@tonic-gate if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue, 22647c478bd9Sstevel@tonic-gate (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) { 22657c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No memory available to dispatch taskq"); 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate static void 22707c478bd9Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head) 22717c478bd9Sstevel@tonic-gate { 22727c478bd9Sstevel@tonic-gate register struct scsi_pkt *pkt; 22737c478bd9Sstevel@tonic-gate register struct amr_command *ac, *localhead; 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate localhead = head; 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate while (localhead) { 22787c478bd9Sstevel@tonic-gate ac = localhead; 22797c478bd9Sstevel@tonic-gate localhead = ac->ac_next; 22807c478bd9Sstevel@tonic-gate ac->ac_next = NULL; 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate pkt = ac->pkt; 22837c478bd9Sstevel@tonic-gate *pkt->pkt_scbp = 0; 22847c478bd9Sstevel@tonic-gate 22857c478bd9Sstevel@tonic-gate if (ac->ac_status == AMR_STATUS_SUCCESS) { 22867c478bd9Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 22877c478bd9Sstevel@tonic-gate | STATE_GOT_TARGET 22887c478bd9Sstevel@tonic-gate | STATE_SENT_CMD 22897c478bd9Sstevel@tonic-gate | STATE_XFERRED_DATA); 22907c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 22917c478bd9Sstevel@tonic-gate } else { 22927c478bd9Sstevel@tonic-gate pkt->pkt_state |= STATE_GOT_BUS 22937c478bd9Sstevel@tonic-gate | STATE_ARQ_DONE; 22947c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 22957c478bd9Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_HARDWARE_ERROR); 22967c478bd9Sstevel@tonic-gate } 22979c57abc8Ssrivijitha dugganapalli if (!(pkt->pkt_flags & FLAG_NOINTR)) { 22989c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt); 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate } 2302