arcmsr.c revision 9106:ee8f18cdafb2
16008Syy154373/* 26008Syy154373 * O.S : Solaris 36008Syy154373 * FILE NAME : arcmsr.c 46008Syy154373 * BY : Erich Chen 56008Syy154373 * Description: SCSI RAID Device Driver for 66008Syy154373 * ARECA RAID Host adapter 76008Syy154373 * 86008Syy154373 * Copyright (C) 2002,2007 Areca Technology Corporation All rights reserved. 96008Syy154373 * Copyright (C) 2002,2007 Erich Chen 106008Syy154373 * Web site: www.areca.com.tw 116008Syy154373 * E-mail: erich@areca.com.tw 126008Syy154373 * 136008Syy154373 * Redistribution and use in source and binary forms, with or without 146008Syy154373 * modification, are permitted provided that the following conditions 156008Syy154373 * are met: 166008Syy154373 * 1. Redistributions of source code must retain the above copyright 176008Syy154373 * notice, this list of conditions and the following disclaimer. 186008Syy154373 * 2. Redistributions in binary form must reproduce the above copyright 196008Syy154373 * notice, this list of conditions and the following disclaimer in the 206008Syy154373 * documentation and/or other materials provided with the distribution. 216008Syy154373 * 3. The party using or redistributing the source code and binary forms 226008Syy154373 * agrees to the disclaimer below and the terms and conditions set forth 236008Syy154373 * herein. 246008Syy154373 * 256008Syy154373 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 266008Syy154373 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 276008Syy154373 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 286008Syy154373 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 296008Syy154373 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 306008Syy154373 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 316008Syy154373 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 326008Syy154373 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 336008Syy154373 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 346008Syy154373 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 356008Syy154373 * SUCH DAMAGE. 366008Syy154373 */ 376008Syy154373 386008Syy154373/* 396008Syy154373 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 406008Syy154373 * Use is subject to license terms. 416008Syy154373 */ 426008Syy154373 436008Syy154373#include <sys/types.h> 446008Syy154373#include <sys/ddidmareq.h> 456008Syy154373#include <sys/scsi/scsi.h> 466008Syy154373#include <sys/ddi.h> 476008Syy154373#include <sys/sunddi.h> 486008Syy154373#include <sys/file.h> 496008Syy154373#include <sys/disp.h> 506008Syy154373#include <sys/signal.h> 516008Syy154373#include <sys/debug.h> 526008Syy154373#include <sys/pci.h> 536008Syy154373#include <sys/policy.h> 546008Syy154373#include <sys/atomic.h> 556008Syy154373 566008Syy154373#include "arcmsr.h" 576008Syy154373 586008Syy154373static int arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd); 596008Syy154373static int arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg, 606008Syy154373 int mode, cred_t *credp, int *rvalp); 616008Syy154373static int arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd); 626008Syy154373static int arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd); 636008Syy154373static int arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt); 646008Syy154373static int arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt); 656008Syy154373static int arcmsr_tran_reset(struct scsi_address *ap, int level); 666008Syy154373static int arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom); 676008Syy154373static int arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value, 686008Syy154373 int whom); 696008Syy154373static int arcmsr_tran_tgt_init(dev_info_t *host_dev_info, 706008Syy154373 dev_info_t *target_dev_info, scsi_hba_tran_t *hosttran, 716008Syy154373 struct scsi_device *sd); 726008Syy154373static void arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt); 736008Syy154373static void arcmsr_tran_destroy_pkt(struct scsi_address *ap, 746008Syy154373 struct scsi_pkt *pkt); 756008Syy154373static void arcmsr_tran_sync_pkt(struct scsi_address *ap, 766008Syy154373 struct scsi_pkt *pkt); 776008Syy154373static struct scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap, 786008Syy154373 struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 796008Syy154373 int tgtlen, int flags, int (*callback)(), caddr_t arg); 806008Syy154373 816008Syy154373static int arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun, 826008Syy154373 dev_info_t **ldip); 836008Syy154373static uint_t arcmsr_interrupt(caddr_t arg); 846008Syy154373static int arcmsr_initialize(struct ACB *acb); 856008Syy154373static int arcmsr_dma_alloc(struct ACB *acb, 866008Syy154373 struct scsi_pkt *pkt, struct buf *bp, int flags, int (*callback)()); 876008Syy154373static int arcmsr_dma_move(struct ACB *acb, 886008Syy154373 struct scsi_pkt *pkt, struct buf *bp); 896008Syy154373static void arcmsr_pcidev_disattach(struct ACB *acb); 906008Syy154373static void arcmsr_ccb_complete(struct CCB *ccb, int flag); 916008Syy154373static void arcmsr_iop_init(struct ACB *acb); 926008Syy154373static void arcmsr_iop_parking(struct ACB *acb); 936008Syy154373static void arcmsr_log(struct ACB *acb, int level, char *fmt, ...); 946008Syy154373static struct CCB *arcmsr_get_freeccb(struct ACB *acb); 956008Syy154373static void arcmsr_flush_hba_cache(struct ACB *acb); 966008Syy154373static void arcmsr_flush_hbb_cache(struct ACB *acb); 976008Syy154373static void arcmsr_stop_hba_bgrb(struct ACB *acb); 986008Syy154373static void arcmsr_stop_hbb_bgrb(struct ACB *acb); 996008Syy154373static void arcmsr_start_hba_bgrb(struct ACB *acb); 1006008Syy154373static void arcmsr_start_hba_bgrb(struct ACB *acb); 1016008Syy154373static void arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb); 1026008Syy154373static void arcmsr_polling_hbb_ccbdone(struct ACB *acb, struct CCB *poll_ccb); 1036008Syy154373static void arcmsr_build_ccb(struct CCB *ccb); 1046008Syy154373static int arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags, 1056008Syy154373 ddi_bus_config_op_t op, void *arg, dev_info_t **childp); 1066008Syy154373static int arcmsr_name_node(dev_info_t *dip, char *name, int len); 1076008Syy154373static dev_info_t *arcmsr_find_child(struct ACB *acb, uint16_t tgt, 1086008Syy154373 uint8_t lun); 1096008Syy154373 1106008Syy154373static struct ACB *ArcMSRHBA[ARCMSR_MAX_ADAPTER]; 1116008Syy154373static int arcmsr_hba_count; 1126008Syy154373static void *arcmsr_soft_state = NULL; 1136008Syy154373static kmutex_t arcmsr_global_mutex; 1146008Syy154373 1156008Syy154373#define MSR_MINOR 32 1166008Syy154373#define INST2MSR(x) (((x) << INST_MINOR_SHIFT) | MSR_MINOR) 1176008Syy154373 1186008Syy154373static ddi_dma_attr_t arcmsr_dma_attr = { 1196008Syy154373 DMA_ATTR_V0, /* ddi_dma_attr version */ 1206008Syy154373 0, /* low DMA address range */ 1216008Syy154373 0xffffffff, /* high DMA address range */ 1226008Syy154373 0x00ffffff, /* DMA counter counter upper bound */ 1236008Syy154373 1, /* DMA address alignment requirements */ 1246008Syy154373 DEFAULT_BURSTSIZE | BURST32 | BURST64, /* burst sizes */ 1256008Syy154373 1, /* minimum effective DMA size */ 1266008Syy154373 ARCMSR_MAX_XFER_LEN, /* maximum DMA xfer size */ 1276008Syy154373 /* 1286008Syy154373 * The dma_attr_seg field supplies the limit of each Scatter/Gather 1296008Syy154373 * list element's "address+length". The Intel IOP331 can not use 1306008Syy154373 * segments over the 4G boundary due to segment boundary restrictions 1316008Syy154373 */ 1326008Syy154373 0x00ffffff, 1336008Syy154373 ARCMSR_MAX_SG_ENTRIES, /* scatter/gather list count */ 1346008Syy154373 1, /* device granularity */ 1356008Syy154373 DDI_DMA_FORCE_PHYSICAL /* Bus specific DMA flags */ 1366008Syy154373}; 1376008Syy154373 1386008Syy154373static ddi_dma_attr_t arcmsr_ccb_attr = { 1396008Syy154373 DMA_ATTR_V0, /* ddi_dma_attr version */ 1406008Syy154373 0, /* low DMA address range */ 1416008Syy154373 0xffffffff, /* high DMA address range */ 1426008Syy154373 0x00ffffff, /* DMA counter counter upper bound */ 1436008Syy154373 1, /* default byte alignment */ 1446008Syy154373 DEFAULT_BURSTSIZE | BURST32 | BURST64, /* burst sizes */ 1456008Syy154373 1, /* minimum effective DMA size */ 1466008Syy154373 0xffffffff, /* maximum DMA xfer size */ 1476008Syy154373 0x00ffffff, /* max segment size, segment boundary restrictions */ 1486008Syy154373 1, /* scatter/gather list count */ 1496008Syy154373 1, /* device granularity */ 1506008Syy154373 DDI_DMA_FORCE_PHYSICAL /* Bus specific DMA flags */ 1516008Syy154373}; 1526008Syy154373 1536008Syy154373static struct cb_ops arcmsr_cb_ops = { 1546008Syy154373 scsi_hba_open, /* open(9E) */ 1556008Syy154373 scsi_hba_close, /* close(9E) */ 1566008Syy154373 nodev, /* strategy(9E), returns ENXIO */ 1576008Syy154373 nodev, /* print(9E) */ 1586008Syy154373 nodev, /* dump(9E) Cannot be used as a dump device */ 1596008Syy154373 nodev, /* read(9E) */ 1606008Syy154373 nodev, /* write(9E) */ 1616008Syy154373 arcmsr_cb_ioctl, /* ioctl(9E) */ 1626008Syy154373 nodev, /* devmap(9E) */ 1636008Syy154373 nodev, /* mmap(9E) */ 1646008Syy154373 nodev, /* segmap(9E) */ 1656008Syy154373 NULL, /* chpoll(9E) returns ENXIO */ 1666008Syy154373 nodev, /* prop_op(9E) */ 1676008Syy154373 NULL, /* streamtab(9S) */ 1686008Syy154373#ifdef _LP64 1696008Syy154373 /* 1706008Syy154373 * cb_ops cb_flag: 1716008Syy154373 * D_NEW | D_MP compatibility flags, see conf.h 1726008Syy154373 * D_MP flag indicates that the driver is safe for 1736008Syy154373 * multi-threaded operation 1746008Syy154373 * D_64BIT flag driver properly handles 64-bit offsets 1756008Syy154373 */ 1766008Syy154373 D_HOTPLUG | D_MP | D_64BIT, 1776008Syy154373#else 1786008Syy154373 D_HOTPLUG | D_MP, 1796008Syy154373#endif 1806008Syy154373 CB_REV, 1816008Syy154373 nodev, /* aread(9E) */ 1826008Syy154373 nodev /* awrite(9E) */ 1836008Syy154373}; 1846008Syy154373 1856008Syy154373static struct dev_ops arcmsr_ops = { 1866008Syy154373 DEVO_REV, /* devo_rev */ 1876008Syy154373 0, /* reference count */ 1886008Syy154373 nodev, /* getinfo */ 1896008Syy154373 nulldev, /* identify */ 1906008Syy154373 nulldev, /* probe */ 1916008Syy154373 arcmsr_attach, /* attach */ 1926008Syy154373 arcmsr_detach, /* detach */ 1936008Syy154373 arcmsr_reset, /* reset, shutdown, reboot notify */ 1946008Syy154373 &arcmsr_cb_ops, /* driver operations */ 1956008Syy154373 NULL, /* bus operations */ 1966008Syy154373 nulldev /* power */ 1976008Syy154373}; 1986008Syy154373 1996008Syy154373char _depends_on[] = "misc/scsi"; 2006008Syy154373 2016008Syy154373static struct modldrv arcmsr_modldrv = { 2026008Syy154373 &mod_driverops, /* Type of module. This is a driver. */ 2036008Syy154373 ARCMSR_DRIVER_VERSION, /* module name, from arcmsr.h */ 2046008Syy154373 &arcmsr_ops, /* driver ops */ 2056008Syy154373}; 2066008Syy154373 2076008Syy154373static struct modlinkage arcmsr_modlinkage = { 2086008Syy154373 MODREV_1, 2096008Syy154373 &arcmsr_modldrv, 2106008Syy154373 NULL 2116008Syy154373}; 2126008Syy154373 2136008Syy154373 2146008Syy154373int 2156008Syy154373_init(void) { 2166008Syy154373 int ret; 2176008Syy154373 2186008Syy154373 2196008Syy154373 mutex_init(&arcmsr_global_mutex, "arcmsr global mutex", 2206008Syy154373 MUTEX_DRIVER, NULL); 2216008Syy154373 ret = ddi_soft_state_init(&arcmsr_soft_state, 2226008Syy154373 sizeof (struct ACB), ARCMSR_MAX_ADAPTER); 2236008Syy154373 if (ret != 0) { 2246008Syy154373 return (ret); 2256008Syy154373 } 2266008Syy154373 if ((ret = scsi_hba_init(&arcmsr_modlinkage)) != 0) { 2276008Syy154373 ddi_soft_state_fini(&arcmsr_soft_state); 2286008Syy154373 return (ret); 2296008Syy154373 } 2306008Syy154373 2316008Syy154373 if ((ret = mod_install(&arcmsr_modlinkage)) != 0) { 2326008Syy154373 mutex_destroy(&arcmsr_global_mutex); 2336008Syy154373 scsi_hba_fini(&arcmsr_modlinkage); 2346008Syy154373 if (arcmsr_soft_state != NULL) { 2356008Syy154373 ddi_soft_state_fini(&arcmsr_soft_state); 2366008Syy154373 } 2376008Syy154373 } 2386008Syy154373 return (ret); 2396008Syy154373} 2406008Syy154373 2416008Syy154373 2426008Syy154373int 2436008Syy154373_fini(void) { 2446008Syy154373 int ret; 2456008Syy154373 2466008Syy154373 ret = mod_remove(&arcmsr_modlinkage); 2476008Syy154373 if (ret == 0) { 2486008Syy154373 /* if ret = 0 , said driver can remove */ 2496008Syy154373 mutex_destroy(&arcmsr_global_mutex); 2506008Syy154373 scsi_hba_fini(&arcmsr_modlinkage); 2516008Syy154373 if (arcmsr_soft_state != NULL) { 2526008Syy154373 ddi_soft_state_fini(&arcmsr_soft_state); 2536008Syy154373 } 2546008Syy154373 } 2556008Syy154373 return (ret); 2566008Syy154373} 2576008Syy154373 2586008Syy154373 2596008Syy154373int 2606008Syy154373_info(struct modinfo *modinfop) { 2616008Syy154373 return (mod_info(&arcmsr_modlinkage, modinfop)); 2626008Syy154373} 2636008Syy154373 2646008Syy154373 2656008Syy154373 2666008Syy154373#if defined(ARCMSR_DEBUG) 2676008Syy154373static void 2686008Syy154373arcmsr_dump_scsi_cdb(struct scsi_address *ap, struct scsi_pkt *pkt) { 2696008Syy154373 2706008Syy154373 static char hex[] = "0123456789abcdef"; 2716008Syy154373 struct ACB *acb = 2726008Syy154373 (struct ACB *)ap->a_hba_tran->tran_hba_private; 2736008Syy154373 struct CCB *ccb = 2746008Syy154373 (struct CCB *)pkt->pkt_ha_private; 2756008Syy154373 uint8_t *cdb = pkt->pkt_cdbp; 2766008Syy154373 char buf [256]; 2776008Syy154373 char *p; 2786008Syy154373 int i; 2796008Syy154373 2806008Syy154373 2816008Syy154373 (void) sprintf(buf, "arcmsr%d: sgcount=%d <%d, %d> " 2826008Syy154373 "cdb ", 2836008Syy154373 ddi_get_instance(acb->dev_info), ccb->arcmsr_cdb.sgcount, 2846008Syy154373 ap->a_target, ap->a_lun); 2856008Syy154373 2866008Syy154373 p = buf + strlen(buf); 2876008Syy154373 *p++ = '['; 2886008Syy154373 2896008Syy154373 for (i = 0; i < ccb->arcmsr_cdb.CdbLength; i++, cdb++) { 2906008Syy154373 if (i != 0) { 2916008Syy154373 *p++ = ' '; 2926008Syy154373 } 2936008Syy154373 *p++ = hex[(*cdb >> 4) & 0x0f]; 2946008Syy154373 *p++ = hex[*cdb & 0x0f]; 2956008Syy154373 } 2966008Syy154373 *p++ = ']'; 2976008Syy154373 *p++ = '.'; 2986008Syy154373 *p = 0; 2996008Syy154373 cmn_err(CE_CONT, buf); 3006008Syy154373} 3016008Syy154373#endif /* ARCMSR_DEBUG */ 3026008Syy154373 3036008Syy154373static void 3046008Syy154373arcmsr_devmap_req_timeout(void* arg) { 3056008Syy154373 3066008Syy154373 struct ACB *acb = (struct ACB *)arg; 3076008Syy154373 switch (acb->adapter_type) { 3086008Syy154373 case ACB_ADAPTER_TYPE_A: 3096008Syy154373 { 3106008Syy154373 struct HBA_msgUnit *phbamu; 3116008Syy154373 3126008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 3136008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 3146008Syy154373 &phbamu->inbound_msgaddr0, 3156008Syy154373 ARCMSR_INBOUND_MESG0_GET_CONFIG); 3166008Syy154373 } 3176008Syy154373 break; 3186008Syy154373 case ACB_ADAPTER_TYPE_B: 3196008Syy154373 { 3206008Syy154373 struct HBB_msgUnit *phbbmu; 3216008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 3226008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 3236008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 3246008Syy154373 ARCMSR_MESSAGE_GET_CONFIG); 3256008Syy154373 } 3266008Syy154373 break; 3276008Syy154373 } 3286008Syy154373 3296008Syy154373 if ((acb->timeout_id != 0) && 3306008Syy154373 ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) { 3316008Syy154373 /* do pkt timeout check each 5 secs */ 3326008Syy154373 acb->timeout_id = timeout(arcmsr_devmap_req_timeout, 3336008Syy154373 (void*)acb, (5 * drv_usectohz(1000000))); 3346008Syy154373 } 3356008Syy154373} 3366008Syy154373 3376008Syy154373 3386008Syy154373static void 3396008Syy154373arcmsr_ccbs_timeout(void* arg) { 3406008Syy154373 3416008Syy154373 struct ACB *acb = (struct ACB *)arg; 3426008Syy154373 struct CCB *ccb; 3436008Syy154373 int i; 3446008Syy154373 int current_time = ddi_get_time(); 3456008Syy154373 3466008Syy154373 3476008Syy154373 if (acb->ccboutstandingcount != 0) { 3486008Syy154373 /* check each ccb */ 3496008Syy154373 i = ddi_dma_sync(acb->ccbs_pool_handle, 0, 3506008Syy154373 acb->dma_sync_size, DDI_DMA_SYNC_FORKERNEL); 3516008Syy154373 if (i != DDI_SUCCESS) { 3526008Syy154373 if ((acb->timeout_id != 0) && 3536008Syy154373 ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) { 3546008Syy154373 /* do pkt timeout check each 60 secs */ 3556008Syy154373 acb->timeout_id = timeout(arcmsr_ccbs_timeout, 3566008Syy154373 (void*)acb, 3576008Syy154373 (60 * drv_usectohz(1000000))); 3586008Syy154373 } 3596008Syy154373 return; 3606008Syy154373 } 3616008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 3626008Syy154373 ccb = acb->pccb_pool[i]; 3636008Syy154373 if (ccb->acb != acb) { 3646008Syy154373 break; 3656008Syy154373 } 3666008Syy154373 if (ccb->startdone == ARCMSR_CCB_DONE) { 3676008Syy154373 continue; 3686008Syy154373 } 3696008Syy154373 if (ccb->pkt == NULL) { 3706008Syy154373 continue; 3716008Syy154373 } 3726008Syy154373 if (ccb->pkt->pkt_time == 0) { 3736008Syy154373 continue; 3746008Syy154373 } 3756008Syy154373 if ((int)ccb->ccb_time >= current_time) { 3766008Syy154373 continue; 3776008Syy154373 } 3786008Syy154373 if (ccb->startdone == ARCMSR_CCB_START) { 3796008Syy154373 int id = ccb->pkt->pkt_address.a_target; 3806008Syy154373 int lun = ccb->pkt->pkt_address.a_lun; 3816008Syy154373 3826008Syy154373 /* 3836008Syy154373 * handle outstanding command of timeout ccb 3846008Syy154373 */ 3856008Syy154373 ccb->pkt->pkt_reason = CMD_TIMEOUT; 3866008Syy154373 ccb->pkt->pkt_statistics = STAT_TIMEOUT; 3876008Syy154373 3886008Syy154373 cmn_err(CE_CONT, 3896008Syy154373 "arcmsr%d: scsi target %d lun %d " 3906008Syy154373 "outstanding command timeout", 3916008Syy154373 ddi_get_instance(acb->dev_info), 3926008Syy154373 id, lun); 3936008Syy154373 cmn_err(CE_CONT, 3946008Syy154373 "arcmsr%d: scsi target %d lun %d " 3956008Syy154373 "fatal error on target, device is gone", 3966008Syy154373 ddi_get_instance(acb->dev_info), 3976008Syy154373 id, lun); 3986008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GONE; 3996008Syy154373 arcmsr_ccb_complete(ccb, 1); 4006008Syy154373 acb->timeout_count++; 4016008Syy154373 continue; 4026008Syy154373 } 4036008Syy154373 ccb->ccb_time = (time_t)(ccb->pkt->pkt_time + 4046008Syy154373 current_time); /* adjust ccb_time of pending ccb */ 4056008Syy154373 } 4066008Syy154373 } 4076008Syy154373 if ((acb->timeout_id != 0) && 4086008Syy154373 ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) { 4096008Syy154373 /* do pkt timeout check each 60 secs */ 4106008Syy154373 acb->timeout_id = timeout(arcmsr_ccbs_timeout, 4116008Syy154373 (void*)acb, (60 * drv_usectohz(1000000))); 4126008Syy154373 } 4136008Syy154373} 4146008Syy154373 4156008Syy154373 4166008Syy154373static uint32_t 4176008Syy154373arcmsr_disable_allintr(struct ACB *acb) { 4186008Syy154373 4196008Syy154373 uint32_t intmask_org; 4206008Syy154373 4216008Syy154373 switch (acb->adapter_type) { 4226008Syy154373 case ACB_ADAPTER_TYPE_A: { 4236008Syy154373 struct HBA_msgUnit *phbamu = 4246008Syy154373 (struct HBA_msgUnit *)acb->pmu; 4256008Syy154373 4266008Syy154373 /* disable all outbound interrupt */ 4276008Syy154373 intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 4286008Syy154373 &phbamu->outbound_intmask); 4296008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 4306008Syy154373 &phbamu->outbound_intmask, 4316008Syy154373 intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE); 4326008Syy154373 } 4336008Syy154373 break; 4346008Syy154373 case ACB_ADAPTER_TYPE_B: { 4356008Syy154373 struct HBB_msgUnit *phbbmu = 4366008Syy154373 (struct HBB_msgUnit *)acb->pmu; 4376008Syy154373 4386008Syy154373 /* disable all outbound interrupt */ 4396008Syy154373 intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 4406008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell_mask); 4416008Syy154373 /* disable all interrupts */ 4426008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 4436008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell_mask, 0); 4446008Syy154373 } 4456008Syy154373 break; 4466008Syy154373 } 4476008Syy154373 return (intmask_org); 4486008Syy154373} 4496008Syy154373 4506008Syy154373 4516008Syy154373static void 4526008Syy154373arcmsr_enable_allintr(struct ACB *acb, uint32_t intmask_org) { 4536008Syy154373 4546008Syy154373 int mask; 4556008Syy154373 4566008Syy154373 switch (acb->adapter_type) { 4576008Syy154373 case ACB_ADAPTER_TYPE_A: { 4586008Syy154373 struct HBA_msgUnit *phbamu = 4596008Syy154373 (struct HBA_msgUnit *)acb->pmu; 4606008Syy154373 4616008Syy154373 /* 4626008Syy154373 * enable outbound Post Queue, outbound doorbell message0 4636008Syy154373 * Interrupt 4646008Syy154373 */ 4656008Syy154373 mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | 4666008Syy154373 ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE | 4676008Syy154373 ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); 4686008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 4696008Syy154373 &phbamu->outbound_intmask, intmask_org & mask); 4706008Syy154373 acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; 4716008Syy154373 } 4726008Syy154373 break; 4736008Syy154373 case ACB_ADAPTER_TYPE_B: { 4746008Syy154373 struct HBB_msgUnit *phbbmu = 4756008Syy154373 (struct HBB_msgUnit *)acb->pmu; 4766008Syy154373 4776008Syy154373 mask = (ARCMSR_IOP2DRV_DATA_WRITE_OK | 4786008Syy154373 ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE | 4796008Syy154373 ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); 4806008Syy154373 /* 1=interrupt enable, 0=interrupt disable */ 4816008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 4826008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell_mask, 4836008Syy154373 intmask_org | mask); 4846008Syy154373 acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; 4856008Syy154373 } 4866008Syy154373 break; 4876008Syy154373 } 4886008Syy154373} 4896008Syy154373 4906008Syy154373 4916008Syy154373static void 4926008Syy154373arcmsr_iop_parking(struct ACB *acb) { 4936008Syy154373 4946008Syy154373 if (acb != NULL) { 4956008Syy154373 /* stop adapter background rebuild */ 4966008Syy154373 if (acb->acb_flags & ACB_F_MSG_START_BGRB) { 4976008Syy154373 uint32_t intmask_org; 4986008Syy154373 4996008Syy154373 acb->acb_flags &= ~ACB_F_MSG_START_BGRB; 5006008Syy154373 /* disable all outbound interrupt */ 5016008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 5026008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 5036008Syy154373 arcmsr_stop_hba_bgrb(acb); 5046008Syy154373 arcmsr_flush_hba_cache(acb); 5056008Syy154373 } else { 5066008Syy154373 arcmsr_stop_hbb_bgrb(acb); 5076008Syy154373 arcmsr_flush_hbb_cache(acb); 5086008Syy154373 } 5096008Syy154373 /* 5106008Syy154373 * enable outbound Post Queue 5116008Syy154373 * enable outbound doorbell Interrupt 5126008Syy154373 */ 5136008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 5146008Syy154373 } 5156008Syy154373 } 5166008Syy154373} 5176008Syy154373 5186008Syy154373 5196008Syy154373 5206008Syy154373static int 5216008Syy154373arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd) { 5226008Syy154373 5236008Syy154373 struct ACB *acb; 5246008Syy154373 scsi_hba_tran_t *scsi_hba_transport; 5256008Syy154373 5266008Syy154373 scsi_hba_transport = (scsi_hba_tran_t *) 5276008Syy154373 ddi_get_driver_private(resetdev); 5286008Syy154373 5296008Syy154373 if (!scsi_hba_transport) 5306008Syy154373 return (DDI_FAILURE); 5316008Syy154373 5326008Syy154373 acb = (struct ACB *) 5336008Syy154373 scsi_hba_transport->tran_hba_private; 5346008Syy154373 5356008Syy154373 if (!acb) 5366008Syy154373 return (DDI_FAILURE); 5376008Syy154373 5386008Syy154373 if ((cmd == RESET_LUN) || 5396008Syy154373 (cmd == RESET_BUS) || 5406008Syy154373 (cmd == RESET_TARGET)) 5416008Syy154373 arcmsr_log(NULL, CE_WARN, 5426008Syy154373 "arcmsr%d: reset op (%d) not supported", 5436008Syy154373 ddi_get_instance(resetdev), cmd); 5446008Syy154373 5456008Syy154373 arcmsr_pcidev_disattach(acb); 5466008Syy154373 5476008Syy154373 return (DDI_SUCCESS); 5486008Syy154373} 5496008Syy154373 5506008Syy154373static int 5516008Syy154373arcmsr_do_ddi_attach(dev_info_t *dev_info, int instance) { 5526008Syy154373 5536008Syy154373 scsi_hba_tran_t *hba_trans; 5546008Syy154373 ddi_device_acc_attr_t dev_acc_attr; 5556008Syy154373 struct ACB *acb; 5566008Syy154373 static char buf[256]; 5576008Syy154373 uint16_t wval; 5586008Syy154373 int raid6 = 1; 5596008Syy154373 char *type; 5606008Syy154373 5616008Syy154373 /* 5626008Syy154373 * Soft State Structure 5636008Syy154373 * The driver should allocate the per-device-instance 5646008Syy154373 * soft state structure, being careful to clean up properly if 5656008Syy154373 * an error occurs. Allocate data structure. 5666008Syy154373 */ 5676008Syy154373 if (ddi_soft_state_zalloc(arcmsr_soft_state, instance) 5686008Syy154373 != DDI_SUCCESS) { 5696008Syy154373 arcmsr_log(NULL, CE_WARN, 5706008Syy154373 "arcmsr%d: ddi_soft_state_zalloc failed", 5716008Syy154373 instance); 5726008Syy154373 return (DDI_FAILURE); 5736008Syy154373 } 5746008Syy154373 5756008Syy154373 acb = ddi_get_soft_state(arcmsr_soft_state, instance); 5766008Syy154373 if (acb == NULL) { 5776008Syy154373 arcmsr_log(NULL, CE_WARN, 5786008Syy154373 "arcmsr%d: ddi_get_soft_state failed", 5796008Syy154373 instance); 5806008Syy154373 goto error_level_1; 5816008Syy154373 } 5826008Syy154373 5836008Syy154373 /* acb is already zalloc()d so we don't need to bzero() it */ 5846008Syy154373 dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5856008Syy154373 dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5866008Syy154373 dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 5876008Syy154373 5886008Syy154373 acb->dev_info = dev_info; 5896008Syy154373 acb->dev_acc_attr = dev_acc_attr; 5906008Syy154373 5916008Syy154373 /* 5926008Syy154373 * The driver, if providing DMA, should also check that its hardware is 5936008Syy154373 * installed in a DMA-capable slot 5946008Syy154373 */ 5956008Syy154373 if (ddi_slaveonly(dev_info) == DDI_SUCCESS) { 5966008Syy154373 arcmsr_log(NULL, CE_WARN, 5976008Syy154373 "arcmsr%d: hardware is not installed in a " 5986008Syy154373 "DMA-capable slot", 5996008Syy154373 instance); 6006008Syy154373 goto error_level_0; 6016008Syy154373 } 6026008Syy154373 /* We do not support adapter drivers with high-level interrupts */ 6036008Syy154373 if (ddi_intr_hilevel(dev_info, 0) != 0) { 6046008Syy154373 arcmsr_log(NULL, CE_WARN, 6056008Syy154373 "arcmsr%d: high-level interrupt not supported", 6066008Syy154373 instance); 6076008Syy154373 goto error_level_0; 6086008Syy154373 } 6096008Syy154373 6106008Syy154373 if (pci_config_setup(dev_info, &acb->pci_acc_handle) 6116008Syy154373 != DDI_SUCCESS) { 6126008Syy154373 arcmsr_log(NULL, CE_NOTE, 6136008Syy154373 "arcmsr%d: pci_config_setup() failed, attach failed", 6146008Syy154373 instance); 6156008Syy154373 return (DDI_PROBE_FAILURE); 6166008Syy154373 } 6176008Syy154373 6186008Syy154373 wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_VENID); 6196008Syy154373 if (wval != PCI_VENDOR_ID_ARECA) { 6206008Syy154373 arcmsr_log(NULL, CE_NOTE, 6216008Syy154373 "arcmsr%d: failing attach: 'vendorid (0x%04x) " 6226008Syy154373 "does not match 0x%04x (PCI_VENDOR_ID_ARECA)\n", 6236008Syy154373 instance, wval, PCI_VENDOR_ID_ARECA); 6246008Syy154373 return (DDI_PROBE_FAILURE); 6256008Syy154373 } 6266008Syy154373 6276008Syy154373 wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_DEVID); 6286008Syy154373 switch (wval) { 6296008Syy154373 case PCI_DEVICE_ID_ARECA_1110: 6306008Syy154373 case PCI_DEVICE_ID_ARECA_1210: 6316008Syy154373 case PCI_DEVICE_ID_ARECA_1201: 6326008Syy154373 raid6 = 0; 6336008Syy154373 /*FALLTHRU*/ 6346008Syy154373 case PCI_DEVICE_ID_ARECA_1120: 6356008Syy154373 case PCI_DEVICE_ID_ARECA_1130: 6366008Syy154373 case PCI_DEVICE_ID_ARECA_1160: 6376008Syy154373 case PCI_DEVICE_ID_ARECA_1170: 6386008Syy154373 case PCI_DEVICE_ID_ARECA_1220: 6396008Syy154373 case PCI_DEVICE_ID_ARECA_1230: 6406008Syy154373 case PCI_DEVICE_ID_ARECA_1260: 6416008Syy154373 case PCI_DEVICE_ID_ARECA_1270: 6426008Syy154373 case PCI_DEVICE_ID_ARECA_1280: 6436008Syy154373 type = "SATA"; 6446008Syy154373 break; 6456008Syy154373 case PCI_DEVICE_ID_ARECA_1380: 6466008Syy154373 case PCI_DEVICE_ID_ARECA_1381: 6476008Syy154373 case PCI_DEVICE_ID_ARECA_1680: 6486008Syy154373 case PCI_DEVICE_ID_ARECA_1681: 6496008Syy154373 type = "SAS"; 6506008Syy154373 break; 6516008Syy154373 default: 6526008Syy154373 type = "X-TYPE"; 6536008Syy154373 break; 6546008Syy154373 } 6556008Syy154373 6566008Syy154373 (void) sprintf(buf, "Areca %s Host Adapter RAID Controller%s", 6576008Syy154373 type, raid6 ? " (RAID6 capable)" : ""); 6586008Syy154373 cmn_err(CE_CONT, "arcmsr%d:%s ", instance, buf); 6596008Syy154373 cmn_err(CE_CONT, "arcmsr%d:%s ", instance, ARCMSR_DRIVER_VERSION); 6606008Syy154373 6616008Syy154373 6626008Syy154373 /* we disable iop interrupt here */ 6636008Syy154373 if (arcmsr_initialize(acb) == DDI_FAILURE) { 6646008Syy154373 arcmsr_log(NULL, CE_WARN, "arcmsr%d: arcmsr_initialize " 6656008Syy154373 "failed", instance); 6666008Syy154373 goto error_level_1; 6676008Syy154373 } 6686008Syy154373 6696008Syy154373 /* 6706008Syy154373 * The driver must first obtain the iblock cookie to initialize 6716008Syy154373 * mutexes used in the driver handler. Only after those mutexes 6726008Syy154373 * have been initialized can the interrupt handler be added. 6736008Syy154373 */ 6746008Syy154373 if (ddi_get_iblock_cookie(dev_info, 0, &acb->iblock_cookie) 6756008Syy154373 != DDI_SUCCESS) { 6766008Syy154373 arcmsr_log(NULL, CE_WARN, "arcmsr%d: " 6776008Syy154373 "ddi_get_iblock_cookie failed", instance); 6786008Syy154373 goto error_level_2; 6796008Syy154373 } 6806008Syy154373 mutex_init(&acb->acb_mutex, NULL, MUTEX_DRIVER, 6816008Syy154373 (void *)acb->iblock_cookie); 6826008Syy154373 mutex_init(&acb->postq_mutex, NULL, MUTEX_DRIVER, 6836008Syy154373 (void *)acb->iblock_cookie); 6846008Syy154373 mutex_init(&acb->workingQ_mutex, NULL, MUTEX_DRIVER, 6856008Syy154373 (void *)acb->iblock_cookie); 6866008Syy154373 mutex_init(&acb->ioctl_mutex, NULL, MUTEX_DRIVER, 6876008Syy154373 (void *)acb->iblock_cookie); 6886008Syy154373 6896008Syy154373 /* Allocate a transport structure */ 6906008Syy154373 hba_trans = scsi_hba_tran_alloc(dev_info, SCSI_HBA_CANSLEEP); 6916008Syy154373 if (hba_trans == NULL) { 6926008Syy154373 arcmsr_log(NULL, CE_WARN, 6936008Syy154373 "arcmsr%d: scsi_hba_tran_alloc failed", 6946008Syy154373 instance); 6956008Syy154373 goto error_level_3; 6966008Syy154373 } 6976008Syy154373 acb->scsi_hba_transport = hba_trans; 6986008Syy154373 acb->dev_info = dev_info; 6996008Syy154373 /* init scsi host adapter transport entry */ 7006008Syy154373 hba_trans->tran_hba_private = acb; 7016008Syy154373 hba_trans->tran_tgt_private = NULL; 7026008Syy154373 /* 7036008Syy154373 * If no per-target initialization is required, the HBA can leave 7046008Syy154373 * tran_tgt_init set to NULL. 7056008Syy154373 */ 7066008Syy154373 hba_trans->tran_tgt_init = arcmsr_tran_tgt_init; 7076008Syy154373 hba_trans->tran_tgt_probe = scsi_hba_probe; 7086008Syy154373 hba_trans->tran_tgt_free = NULL; 7096008Syy154373 hba_trans->tran_start = arcmsr_tran_start; 7106008Syy154373 hba_trans->tran_abort = arcmsr_tran_abort; 7116008Syy154373 hba_trans->tran_reset = arcmsr_tran_reset; 7126008Syy154373 hba_trans->tran_getcap = arcmsr_tran_getcap; 7136008Syy154373 hba_trans->tran_setcap = arcmsr_tran_setcap; 7146008Syy154373 hba_trans->tran_init_pkt = arcmsr_tran_init_pkt; 7156008Syy154373 hba_trans->tran_destroy_pkt = arcmsr_tran_destroy_pkt; 7166008Syy154373 hba_trans->tran_dmafree = arcmsr_tran_dmafree; 7176008Syy154373 hba_trans->tran_sync_pkt = arcmsr_tran_sync_pkt; 7186008Syy154373 7196008Syy154373 hba_trans->tran_reset_notify = NULL; 7206008Syy154373 hba_trans->tran_get_bus_addr = NULL; 7216008Syy154373 hba_trans->tran_get_name = NULL; 7226008Syy154373 hba_trans->tran_quiesce = NULL; 7236008Syy154373 hba_trans->tran_unquiesce = NULL; 7246008Syy154373 hba_trans->tran_bus_reset = NULL; 7256008Syy154373 hba_trans->tran_bus_config = arcmsr_tran_bus_config; 7266008Syy154373 hba_trans->tran_add_eventcall = NULL; 7276008Syy154373 hba_trans->tran_get_eventcookie = NULL; 7286008Syy154373 hba_trans->tran_post_event = NULL; 7296008Syy154373 hba_trans->tran_remove_eventcall = NULL; 7306008Syy154373 7316008Syy154373 /* iop init and enable interrupt here */ 7326008Syy154373 mutex_enter(&arcmsr_global_mutex); 7336008Syy154373 arcmsr_iop_init(acb); 7346008Syy154373 mutex_exit(&arcmsr_global_mutex); 7356008Syy154373 7366008Syy154373 /* Adding an Interrupt Handler */ 7376008Syy154373 if (ddi_add_intr(dev_info, 0, &acb->iblock_cookie, 0, 7386008Syy154373 arcmsr_interrupt, (caddr_t)acb) != DDI_SUCCESS) { 7396008Syy154373 arcmsr_log(NULL, CE_WARN, 7406008Syy154373 "arcmsr%d: failed to add interrupt handler", 7416008Syy154373 instance); 7426008Syy154373 goto error_level_4; 7436008Syy154373 } 7446008Syy154373 /* 7456008Syy154373 * The driver should attach this instance of the device, and 7466008Syy154373 * perform error cleanup if necessary 7476008Syy154373 */ 7486008Syy154373 if (scsi_hba_attach_setup(dev_info, &arcmsr_dma_attr, 7496008Syy154373 hba_trans, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) { 7506008Syy154373 arcmsr_log(NULL, CE_WARN, 7516008Syy154373 "arcmsr%d: scsi_hba_attach_setup failed", 7526008Syy154373 instance); 7536008Syy154373 goto error_level_5; 7546008Syy154373 } 7556008Syy154373 7566008Syy154373 if (ddi_create_minor_node(dev_info, "arcmsr", 7576008Syy154373 S_IFCHR, INST2MSR(instance), DDI_PSEUDO, 0) == DDI_FAILURE) { 7586008Syy154373 arcmsr_log(NULL, CE_WARN, 7596008Syy154373 "arcmsr%d: ddi_create_minor_node fail", instance); 7606008Syy154373 goto error_level_6; 7616008Syy154373 } 7626008Syy154373 7636008Syy154373 7646008Syy154373 /* Initialize power management bookkeeping. */ 7656008Syy154373 if (pm_create_components(dev_info, 1) == DDI_SUCCESS) { 7666008Syy154373 if (pm_idle_component(dev_info, 0) == DDI_FAILURE) { 7676008Syy154373 arcmsr_log(NULL, CE_WARN, 7686008Syy154373 "arcmsr%d: pm_idle_component fail", 7696008Syy154373 instance); 7706008Syy154373 goto error_level_8; 7716008Syy154373 } 7726008Syy154373 pm_set_normal_power(dev_info, 0, 1); 7736008Syy154373 /* acb->power_level = 1; */ 7746008Syy154373 } else { 7756008Syy154373 arcmsr_log(NULL, CE_WARN, 7766008Syy154373 "arcmsr%d: pm_create_components fail", 7776008Syy154373 instance); 7786008Syy154373 goto error_level_7; 7796008Syy154373 } 7806008Syy154373 7816008Syy154373 /* 7826008Syy154373 * Since this driver manages devices with "remote" hardware, " 7836008Syy154373 * i.e. the devices themselves have no "reg" property, the SUSPEND/ 7846008Syy154373 * RESUME commands in detach/attach will not be called by the power 7856008Syy154373 * management framework unless we request it by creating a 7866008Syy154373 * "pm-hardware-state" property and setting it to value 7876008Syy154373 * "needs-suspend-resume". 7886008Syy154373 */ 7896008Syy154373 if (ddi_prop_update_string(DDI_DEV_T_NONE, dev_info, 7906008Syy154373 "pm-hardware-state", "needs-suspend-resume") 7916008Syy154373 != DDI_PROP_SUCCESS) { 7926008Syy154373 arcmsr_log(NULL, CE_WARN, 7936008Syy154373 "arcmsr%d: ddi_prop_update(\"pm-hardware-state\")failed", 7946008Syy154373 instance); 7956008Syy154373 goto error_level_8; 7966008Syy154373 } 7976008Syy154373 7986008Syy154373 /* Create a taskq for dealing with dr events */ 7996008Syy154373 if ((acb->taskq = ddi_taskq_create(dev_info, "arcmsr_dr_taskq", 1, 8006008Syy154373 TASKQ_DEFAULTPRI, 0)) == NULL) { 8016008Syy154373 cmn_err(CE_WARN, "ddi_taskq_create failed"); 8026008Syy154373 goto error_level_8; 8036008Syy154373 } 8046008Syy154373 8056008Syy154373 acb->timeout_count = 0; 8066008Syy154373 /* active ccbs "timeout" watchdog */ 8076008Syy154373 acb->timeout_id = timeout(arcmsr_ccbs_timeout, (caddr_t)acb, 8086008Syy154373 (60 * drv_usectohz(1000000))); 8096008Syy154373 acb->timeout_sc_id = timeout(arcmsr_devmap_req_timeout, (caddr_t)acb, 8106008Syy154373 (5 * drv_usectohz(1000000))); 8116008Syy154373 8126008Syy154373 /* report device info */ 8136008Syy154373 ddi_report_dev(dev_info); 8146008Syy154373 ArcMSRHBA[arcmsr_hba_count] = acb; 8156008Syy154373 arcmsr_hba_count++; 8166008Syy154373 8176008Syy154373 return (DDI_SUCCESS); 8186008Syy154373 8196008Syy154373error_level_8: 8206008Syy154373 pm_destroy_components(dev_info); 8216008Syy154373 8226008Syy154373error_level_7: 8236008Syy154373 /* Remove any previously allocated minor nodes */ 8246008Syy154373 ddi_remove_minor_node(dev_info, NULL); 8256008Syy154373 8266008Syy154373error_level_6: 8276008Syy154373 scsi_hba_tran_free(hba_trans); 8286008Syy154373 8296008Syy154373error_level_5: 8306008Syy154373 ddi_remove_intr(dev_info, 0, (void *)acb->iblock_cookie); 8316008Syy154373 8326008Syy154373error_level_4: 8336008Syy154373 scsi_hba_tran_free(hba_trans); 8346008Syy154373 8356008Syy154373error_level_3: 8366008Syy154373 mutex_destroy(&acb->acb_mutex); 8376008Syy154373 mutex_destroy(&acb->postq_mutex); 8386008Syy154373 mutex_destroy(&acb->workingQ_mutex); 8396008Syy154373 mutex_destroy(&acb->ioctl_mutex); 8406008Syy154373 8416008Syy154373error_level_2: 8426008Syy154373 ddi_dma_mem_free(&acb->ccbs_acc_handle); 8436008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 8446008Syy154373 8456008Syy154373error_level_1: 8466008Syy154373 ddi_soft_state_free(arcmsr_soft_state, instance); 8476008Syy154373 8486008Syy154373error_level_0: 8496008Syy154373 return (DDI_FAILURE); 8506008Syy154373} 8516008Syy154373 8526008Syy154373 8536008Syy154373 8546008Syy154373/* 8556008Syy154373 * Function: arcmsr_attach(9E) 8566008Syy154373 * Description: Set up all device state and allocate data structures, 8576008Syy154373 * mutexes, condition variables, etc. for device operation. 8586008Syy154373 * Set mt_attr property for driver to indicate MT-safety. 8596008Syy154373 * Add interrupts needed. 8606008Syy154373 * Input: dev_info_t *dev_info, ddi_attach_cmd_t cmd 8616008Syy154373 * Output: Return DDI_SUCCESS if device is ready, 8626008Syy154373 * else return DDI_FAILURE 8636008Syy154373 */ 8646008Syy154373static int 8656008Syy154373arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd) { 8666008Syy154373 8676008Syy154373 scsi_hba_tran_t *hba_trans; 8686008Syy154373 struct ACB *acb; 8696008Syy154373 8706008Syy154373 8716008Syy154373#if defined(ARCMSR_DEBUG) 8726008Syy154373 arcmsr_log(NULL, CE_NOTE, 8736008Syy154373 "arcmsr_attach called for device %lx (instance %d)", 8746008Syy154373 &dev_info, ddi_get_instance(dev_info)); 8756008Syy154373#endif 8766008Syy154373 switch (cmd) { 8776008Syy154373 case DDI_ATTACH: 8786008Syy154373 return (arcmsr_do_ddi_attach(dev_info, 8796008Syy154373 ddi_get_instance(dev_info))); 8806008Syy154373 case DDI_RESUME: 8816008Syy154373 case DDI_PM_RESUME: 8826008Syy154373 /* 8836008Syy154373 * There is no hardware state to restart and no timeouts to 8846008Syy154373 * restart since we didn't PM_SUSPEND with active cmds or 8856008Syy154373 * active timeouts We just need to unblock waiting threads 8866008Syy154373 * and restart I/O the code for DDI_RESUME is almost identical 8876008Syy154373 * except it uses the suspend flag rather than pm_suspend flag 8886008Syy154373 */ 8896008Syy154373 hba_trans = (scsi_hba_tran_t *)ddi_get_driver_private(dev_info); 8906008Syy154373 if (!hba_trans) { 8916008Syy154373 return (DDI_FAILURE); 8926008Syy154373 } 8936008Syy154373 acb = (struct ACB *) 8946008Syy154373 hba_trans->tran_hba_private; 8956008Syy154373 mutex_enter(&acb->acb_mutex); 8966008Syy154373 arcmsr_iop_init(acb); 8976008Syy154373 8986008Syy154373 /* restart ccbs "timeout" watchdog */ 8996008Syy154373 acb->timeout_count = 0; 9006008Syy154373 acb->timeout_id = timeout(arcmsr_ccbs_timeout, 9016008Syy154373 (caddr_t)acb, (60 * drv_usectohz(1000000))); 9026008Syy154373 acb->timeout_sc_id = timeout(arcmsr_devmap_req_timeout, 9036008Syy154373 (caddr_t)acb, (5 * drv_usectohz(1000000))); 9046008Syy154373 mutex_exit(&acb->acb_mutex); 9056008Syy154373 return (DDI_SUCCESS); 9066008Syy154373 9076008Syy154373 default: 9086008Syy154373 arcmsr_log(NULL, CE_WARN, 9096008Syy154373 "arcmsr%d: ddi attach cmd (%d) unsupported", 9106008Syy154373 cmd, ddi_get_instance(dev_info)); 9116008Syy154373 return (DDI_FAILURE); 9126008Syy154373 } 9136008Syy154373} 9146008Syy154373 9156008Syy154373/* 9166008Syy154373 * Function: arcmsr_detach(9E) 9176008Syy154373 * Description: Remove all device allocation and system resources, disable 9186008Syy154373 * device interrupt. 9196008Syy154373 * Input: dev_info_t *dev_info 9206008Syy154373 * ddi_detach_cmd_t cmd 9216008Syy154373 * Output: Return DDI_SUCCESS if done, 9226008Syy154373 * else returnDDI_FAILURE 9236008Syy154373 */ 9246008Syy154373static int 9256008Syy154373arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd) { 9266008Syy154373 9276008Syy154373 int instance; 9286008Syy154373 struct ACB *acb; 9296008Syy154373 9306008Syy154373 9316008Syy154373 instance = ddi_get_instance(dev_info); 9326008Syy154373 acb = (struct ACB *)ddi_get_soft_state(arcmsr_soft_state, 9336008Syy154373 instance); 9346008Syy154373 if (!acb) { 9356008Syy154373 return (DDI_FAILURE); 9366008Syy154373 } 9376008Syy154373 9386008Syy154373 switch (cmd) { 9396008Syy154373 case DDI_DETACH: 9406008Syy154373 mutex_enter(&acb->acb_mutex); 9416008Syy154373 if (acb->timeout_id != 0) { 9426008Syy154373 mutex_exit(&acb->acb_mutex); 9436008Syy154373 (void) untimeout(acb->timeout_id); 9446008Syy154373 mutex_enter(&acb->acb_mutex); 9456008Syy154373 acb->timeout_id = 0; 9466008Syy154373 } 9476008Syy154373 if (acb->timeout_sc_id != 0) { 9486008Syy154373 mutex_exit(&acb->acb_mutex); 9496008Syy154373 (void) untimeout(acb->timeout_sc_id); 9506008Syy154373 mutex_enter(&acb->acb_mutex); 9516008Syy154373 acb->timeout_sc_id = 0; 9526008Syy154373 } 9536008Syy154373 arcmsr_pcidev_disattach(acb); 9546008Syy154373 /* Remove interrupt set up by ddi_add_intr */ 9556008Syy154373 ddi_remove_intr(dev_info, 0, acb->iblock_cookie); 9566008Syy154373 /* unbind mapping object to handle */ 9576008Syy154373 (void) ddi_dma_unbind_handle(acb->ccbs_pool_handle); 9586008Syy154373 /* Free ccb pool memory */ 9596008Syy154373 ddi_dma_mem_free(&acb->ccbs_acc_handle); 9606008Syy154373 /* Free DMA handle */ 9616008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 9626008Syy154373 ddi_regs_map_free(&acb->reg_mu_acc_handle0); 9636008Syy154373 if (scsi_hba_detach(dev_info) != DDI_SUCCESS) 9646008Syy154373 arcmsr_log(NULL, CE_WARN, 9656008Syy154373 "arcmsr%d: Unable to detach instance cleanly " 9666008Syy154373 "(should not happen)", 9676008Syy154373 ddi_get_instance(dev_info)); 9686008Syy154373 /* free scsi_hba_transport from scsi_hba_tran_alloc */ 9696008Syy154373 scsi_hba_tran_free(acb->scsi_hba_transport); 9706008Syy154373 ddi_remove_minor_node(dev_info, NULL); 9716008Syy154373 ddi_taskq_destroy(acb->taskq); 9726008Syy154373 ddi_prop_remove_all(dev_info); 9736008Syy154373 mutex_exit(&acb->acb_mutex); 9746008Syy154373 mutex_destroy(&acb->acb_mutex); 9756008Syy154373 mutex_destroy(&acb->postq_mutex); 9766008Syy154373 mutex_destroy(&acb->workingQ_mutex); 9776008Syy154373 mutex_destroy(&acb->ioctl_mutex); 9786008Syy154373 pci_config_teardown(&acb->pci_acc_handle); 9796008Syy154373 ddi_set_driver_private(dev_info, NULL); 9806008Syy154373 ddi_soft_state_free(arcmsr_soft_state, instance); 9816008Syy154373 pm_destroy_components(dev_info); 9826008Syy154373 return (DDI_SUCCESS); 9836008Syy154373 case DDI_SUSPEND: 9846008Syy154373 case DDI_PM_SUSPEND: 9856008Syy154373 mutex_enter(&acb->acb_mutex); 9866008Syy154373 if (acb->timeout_id != 0) { 9876008Syy154373 acb->acb_flags |= ACB_F_SCSISTOPADAPTER; 9886008Syy154373 mutex_exit(&acb->acb_mutex); 9896008Syy154373 (void) untimeout(acb->timeout_id); 9906008Syy154373 (void) untimeout(acb->timeout_sc_id); 9916008Syy154373 mutex_enter(&acb->acb_mutex); 9926008Syy154373 acb->timeout_id = 0; 9936008Syy154373 } 9946008Syy154373 9956008Syy154373 if (acb->timeout_sc_id != 0) { 9966008Syy154373 acb->acb_flags |= ACB_F_SCSISTOPADAPTER; 9976008Syy154373 mutex_exit(&acb->acb_mutex); 9986008Syy154373 (void) untimeout(acb->timeout_sc_id); 9996008Syy154373 mutex_enter(&acb->acb_mutex); 10006008Syy154373 acb->timeout_sc_id = 0; 10016008Syy154373 } 10026008Syy154373 10036008Syy154373 /* disable all outbound interrupt */ 10046008Syy154373 (void) arcmsr_disable_allintr(acb); 10056008Syy154373 /* stop adapter background rebuild */ 10066008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 10076008Syy154373 arcmsr_stop_hba_bgrb(acb); 10086008Syy154373 arcmsr_flush_hba_cache(acb); 10096008Syy154373 } else { 10106008Syy154373 arcmsr_stop_hbb_bgrb(acb); 10116008Syy154373 arcmsr_flush_hbb_cache(acb); 10126008Syy154373 } 10136008Syy154373 mutex_exit(&acb->acb_mutex); 10146008Syy154373 return (DDI_SUCCESS); 10156008Syy154373 default: 10166008Syy154373 return (DDI_FAILURE); 10176008Syy154373 } 10186008Syy154373} 10196008Syy154373 10206008Syy154373 10216008Syy154373 10226008Syy154373/* 10236008Syy154373 * Function: arcmsr_tran_tgt_init 10246008Syy154373 * Description: Called when initializing a target device instance. If 10256008Syy154373 * no per-target initialization is required, the HBA 10266008Syy154373 * may leave tran_tgt_init to NULL 10276008Syy154373 * Input: 10286008Syy154373 * dev_info_t *host_dev_info, 10296008Syy154373 * dev_info_t *target_dev_info, 10306008Syy154373 * scsi_hba_tran_t *tran, 10316008Syy154373 * struct scsi_device *sd 10326008Syy154373 * 10336008Syy154373 * Return: DDI_SUCCESS if success, else return DDI_FAILURE 10346008Syy154373 * 10356008Syy154373 * entry point enables the HBA to allocate and/or initialize any per- 10366008Syy154373 * target resources. 10376008Syy154373 * It also enables the HBA to qualify the device's address as valid and 10386008Syy154373 * supportable for that particular HBA. 10396008Syy154373 * By returning DDI_FAILURE, the instance of the target driver for that 10406008Syy154373 * device will not be probed or attached. 10416008Syy154373 * This entry point is not required, and if none is supplied, 10426008Syy154373 * the framework will attempt to probe and attach all possible instances 10436008Syy154373 * of the appropriate target drivers. 10446008Syy154373 */ 10456008Syy154373static int 10466008Syy154373arcmsr_tran_tgt_init(dev_info_t *host_dev_info, dev_info_t *target_dev_info, 10476008Syy154373 scsi_hba_tran_t *hosttran, struct scsi_device *sd) { 10486008Syy154373#ifndef __lock_lint 10496008Syy154373 _NOTE(ARGUNUSED(hosttran, target_dev_info)) 10506008Syy154373#endif 10516008Syy154373 uint16_t target; 10526008Syy154373 uint8_t lun; 10536008Syy154373 struct ACB *acb = (struct ACB *)sd->sd_address.a_hba_tran -> 10546008Syy154373 tran_hba_private; 10556008Syy154373 10566008Syy154373 target = sd->sd_address.a_target; 10576008Syy154373 lun = sd->sd_address.a_lun; 10586008Syy154373 if ((target >= ARCMSR_MAX_TARGETID) || (lun >= ARCMSR_MAX_TARGETLUN)) { 10596008Syy154373 cmn_err(CE_WARN, 10606008Syy154373 "arcmsr%d: (target %d, lun %d) exceeds " 10616008Syy154373 "maximum supported values (%d, %d)", 10626008Syy154373 ddi_get_instance(host_dev_info), 10636008Syy154373 target, lun, ARCMSR_MAX_TARGETID, ARCMSR_MAX_TARGETLUN); 10646008Syy154373 return (DDI_FAILURE); 10656008Syy154373 } 10666008Syy154373 10676008Syy154373 10686008Syy154373 if (ndi_dev_is_persistent_node(target_dev_info) == 0) { 10696008Syy154373 /* 10706008Syy154373 * If no persistent node exist, we don't allow .conf node 10716008Syy154373 * to be created. 10726008Syy154373 */ 10736008Syy154373 if (arcmsr_find_child(acb, target, lun) != NULL) { 10746008Syy154373 if ((ndi_merge_node(target_dev_info, 10756008Syy154373 arcmsr_name_node) != DDI_SUCCESS)) { 10766008Syy154373 return (DDI_SUCCESS); 10776008Syy154373 } 10786008Syy154373 } 10796008Syy154373 return (DDI_FAILURE); 10806008Syy154373 } 10816008Syy154373 10826008Syy154373 return (DDI_SUCCESS); 10836008Syy154373} 10846008Syy154373 10856008Syy154373/* 10866008Syy154373 * Function: arcmsr_tran_getcap(9E) 10876008Syy154373 * Description: Get the capability named, and returnits value. 10886008Syy154373 * Return Values: current value of capability, ifdefined 10896008Syy154373 * -1 ifcapability is not defined 10906008Syy154373 * ------------------------------------------------------ 10916008Syy154373 * Common Capability Strings Array 10926008Syy154373 * ------------------------------------------------------ 10936008Syy154373 * #define SCSI_CAP_DMA_MAX 0 10946008Syy154373 * #define SCSI_CAP_MSG_OUT 1 10956008Syy154373 * #define SCSI_CAP_DISCONNECT 2 10966008Syy154373 * #define SCSI_CAP_SYNCHRONOUS 3 10976008Syy154373 * #define SCSI_CAP_WIDE_XFER 4 10986008Syy154373 * #define SCSI_CAP_PARITY 5 10996008Syy154373 * #define SCSI_CAP_INITIATOR_ID 6 11006008Syy154373 * #define SCSI_CAP_UNTAGGED_QING 7 11016008Syy154373 * #define SCSI_CAP_TAGGED_QING 8 11026008Syy154373 * #define SCSI_CAP_ARQ 9 11036008Syy154373 * #define SCSI_CAP_LINKED_CMDS 10 a 11046008Syy154373 * #define SCSI_CAP_SECTOR_SIZE 11 b 11056008Syy154373 * #define SCSI_CAP_TOTAL_SECTORS 12 c 11066008Syy154373 * #define SCSI_CAP_GEOMETRY 13 d 11076008Syy154373 * #define SCSI_CAP_RESET_NOTIFICATION 14 e 11086008Syy154373 * #define SCSI_CAP_QFULL_RETRIES 15 f 11096008Syy154373 * #define SCSI_CAP_QFULL_RETRY_INTERVAL 16 10 11106008Syy154373 * #define SCSI_CAP_SCSI_VERSION 17 11 11116008Syy154373 * #define SCSI_CAP_INTERCONNECT_TYPE 18 12 11126008Syy154373 * #define SCSI_CAP_LUN_RESET 19 13 11136008Syy154373 */ 11146008Syy154373static int 11156008Syy154373arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom) { 11166008Syy154373 11176008Syy154373 int capability = 0; 11186008Syy154373 struct ACB *acb = 11196008Syy154373 (struct ACB *)ap->a_hba_tran->tran_hba_private; 11206008Syy154373 11216008Syy154373 11226008Syy154373 if (cap == NULL || whom == 0) { 11236008Syy154373 return (DDI_FAILURE); 11246008Syy154373 } 11256008Syy154373 11266008Syy154373 mutex_enter(&arcmsr_global_mutex); 11276008Syy154373 switch (scsi_hba_lookup_capstr(cap)) { 11286008Syy154373 case SCSI_CAP_MSG_OUT: 11296008Syy154373 case SCSI_CAP_DISCONNECT: 11306008Syy154373 case SCSI_CAP_SYNCHRONOUS: 11316008Syy154373 case SCSI_CAP_WIDE_XFER: 11326008Syy154373 case SCSI_CAP_TAGGED_QING: 11336008Syy154373 case SCSI_CAP_UNTAGGED_QING: 11346008Syy154373 case SCSI_CAP_PARITY: 11356008Syy154373 case SCSI_CAP_ARQ: 11366008Syy154373 capability = acb->tgt_scsi_opts[ap->a_target]; 11376008Syy154373 break; 11386008Syy154373 case SCSI_CAP_SECTOR_SIZE: 11396008Syy154373 capability = ARCMSR_DEV_SECTOR_SIZE; 11406008Syy154373 break; 11416008Syy154373 case SCSI_CAP_DMA_MAX: 11426008Syy154373 /* Limit to 16MB max transfer */ 11436008Syy154373 capability = ARCMSR_MAX_XFER_LEN; 11446008Syy154373 break; 11456008Syy154373 case SCSI_CAP_INITIATOR_ID: 11466008Syy154373 capability = ARCMSR_SCSI_INITIATOR_ID; 11476008Syy154373 break; 11486008Syy154373 case SCSI_CAP_GEOMETRY: 11496008Syy154373 /* head , track , cylinder */ 11506008Syy154373 capability = (255 << 16) | 63; 11516008Syy154373 break; 11526008Syy154373 default: 11536008Syy154373 capability = -1; 11546008Syy154373 break; 11556008Syy154373 } 11566008Syy154373 mutex_exit(&arcmsr_global_mutex); 11576008Syy154373 return (capability); 11586008Syy154373} 11596008Syy154373 11606008Syy154373/* 11616008Syy154373 * Function: arcmsr_tran_setcap(9E) 11626008Syy154373 * Description: Set the specific capability. 11636008Syy154373 * Return Values: 1 - capability exists and can be set to new value 11646008Syy154373 * 0 - capability could not be set to new value 11656008Syy154373 * -1 - no such capability 11666008Syy154373 */ 11676008Syy154373static int 11686008Syy154373arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value, 11696008Syy154373 int whom) { 11706008Syy154373#ifndef __lock_lint 11716008Syy154373 _NOTE(ARGUNUSED(value)) 11726008Syy154373#endif 11736008Syy154373 11746008Syy154373 11756008Syy154373 int supported = 0; 11766008Syy154373 struct ACB *acb = 11776008Syy154373 (struct ACB *)ap->a_hba_tran->tran_hba_private; 11786008Syy154373 11796008Syy154373 11806008Syy154373 if (cap == NULL || whom == 0) { 11816008Syy154373 return (-1); 11826008Syy154373 } 11836008Syy154373 11846008Syy154373 mutex_enter(&arcmsr_global_mutex); 11856008Syy154373 switch (supported = scsi_hba_lookup_capstr(cap)) { 11866008Syy154373 case SCSI_CAP_DISCONNECT: /* 2 */ 11876008Syy154373 case SCSI_CAP_SYNCHRONOUS: /* 3 */ 11886008Syy154373 case SCSI_CAP_TAGGED_QING: /* 8 */ 11896008Syy154373 case SCSI_CAP_WIDE_XFER: /* 4 */ 11906008Syy154373 case SCSI_CAP_ARQ: /* 9 auto request sense */ 11916008Syy154373 case SCSI_CAP_TOTAL_SECTORS: /* c */ 11926008Syy154373 acb->tgt_scsi_opts[ap->a_target] |= supported; 11936008Syy154373 supported = 1; 11946008Syy154373 break; 11956008Syy154373 case SCSI_CAP_UNTAGGED_QING: /* 7 */ 11966008Syy154373 case SCSI_CAP_INITIATOR_ID: /* 6 */ 11976008Syy154373 case SCSI_CAP_DMA_MAX: /* 0 */ 11986008Syy154373 case SCSI_CAP_MSG_OUT: /* 1 */ 11996008Syy154373 case SCSI_CAP_PARITY: /* 5 */ 12006008Syy154373 case SCSI_CAP_LINKED_CMDS: /* a */ 12016008Syy154373 case SCSI_CAP_RESET_NOTIFICATION: /* e */ 12026008Syy154373 case SCSI_CAP_SECTOR_SIZE: /* b */ 12036008Syy154373 supported = 0; 12046008Syy154373 break; 12056008Syy154373 default: 12066008Syy154373 supported = -1; 12076008Syy154373 break; 12086008Syy154373 } 12096008Syy154373 mutex_exit(&arcmsr_global_mutex); 12106008Syy154373 return (supported); 12116008Syy154373} 12126008Syy154373 12136008Syy154373 12146008Syy154373 12156008Syy154373static void 12166008Syy154373arcmsr_free_ccb(struct CCB *ccb) { 12176008Syy154373 12186008Syy154373 struct ACB *acb = ccb->acb; 12196008Syy154373 12206008Syy154373 ccb->startdone = ARCMSR_CCB_DONE; 12216008Syy154373 ccb->pkt = NULL; 12226008Syy154373 ccb->ccb_flags = 0; 12236008Syy154373 mutex_enter(&acb->workingQ_mutex); 12246008Syy154373 acb->ccbworkingQ[acb->workingccb_doneindex] = ccb; 12256008Syy154373 acb->workingccb_doneindex++; 12266008Syy154373 acb->workingccb_doneindex %= ARCMSR_MAX_FREECCB_NUM; 12276008Syy154373 mutex_exit(&acb->workingQ_mutex); 12286008Syy154373} 12296008Syy154373 12306008Syy154373/* 12316008Syy154373 * Function: arcmsr_tran_init_pkt 12326008Syy154373 * Return Values: pointer to scsi_pkt, or NULL 12336008Syy154373 * Description: simultaneously allocate both a scsi_pkt(9S) structure and 12346008Syy154373 * DMA resources for that pkt. 12356008Syy154373 * Called by kernel on behalf of a target driver 12366008Syy154373 * calling scsi_init_pkt(9F). 12376008Syy154373 * Refer to tran_init_pkt(9E) man page 12386008Syy154373 * Context: Can be called from different kernel process threads. 12396008Syy154373 * Can be called by interrupt thread. 12406008Syy154373 * Allocates SCSI packet and DMA resources 12416008Syy154373 */ 12426008Syy154373static struct 12436008Syy154373scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap, 12446008Syy154373 register struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 12456008Syy154373 int tgtlen, int flags, int (*callback)(), caddr_t arg) { 12466008Syy154373 12476008Syy154373 struct CCB *ccb; 12486008Syy154373 struct ARCMSR_CDB *arcmsr_cdb; 12496008Syy154373 struct ACB *acb; 12506008Syy154373 int old_pkt_flag = 1; 12516008Syy154373 12526008Syy154373 12536008Syy154373 acb = (struct ACB *)ap->a_hba_tran->tran_hba_private; 12546008Syy154373 12556008Syy154373 if (pkt == NULL) { 12566008Syy154373 /* get free CCB */ 12576008Syy154373 ccb = arcmsr_get_freeccb(acb); 12586008Syy154373 if (ccb == (struct CCB *)NULL) { 12596008Syy154373 return (NULL); 12606008Syy154373 } 12616008Syy154373 12626008Syy154373 if (ccb->pkt != NULL) { 12636008Syy154373 /* 12646008Syy154373 * If kmem_flags are turned on, expect to 12656008Syy154373 * see a message 12666008Syy154373 */ 12676008Syy154373 cmn_err(CE_WARN, "arcmsr%d: invalid pkt", 12686008Syy154373 ddi_get_instance(acb->dev_info)); 12696008Syy154373 return (NULL); 12706008Syy154373 } 12716008Syy154373 pkt = scsi_hba_pkt_alloc(acb->dev_info, ap, cmdlen, 12726008Syy154373 statuslen, tgtlen, sizeof (struct scsi_pkt), 12736008Syy154373 callback, arg); 12746008Syy154373 if (pkt == NULL) { 12756008Syy154373 cmn_err(CE_WARN, 12766008Syy154373 "arcmsr%d: scsi pkt allocation failed", 12776008Syy154373 ddi_get_instance(acb->dev_info)); 12786008Syy154373 arcmsr_free_ccb(ccb); 12796008Syy154373 return (NULL); 12806008Syy154373 } 12816008Syy154373 /* Initialize CCB */ 12826008Syy154373 ccb->pkt = pkt; 12836008Syy154373 ccb->pkt_dma_handle = NULL; 12846008Syy154373 /* record how many sg are needed to xfer on this pkt */ 12856008Syy154373 ccb->pkt_ncookies = 0; 12866008Syy154373 /* record how many sg we got from this window */ 12876008Syy154373 ccb->pkt_cookie = 0; 12886008Syy154373 /* record how many windows have partial dma map set */ 12896008Syy154373 ccb->pkt_nwin = 0; 12906008Syy154373 /* record current sg window position */ 12916008Syy154373 ccb->pkt_curwin = 0; 12926008Syy154373 ccb->pkt_dma_len = 0; 12936008Syy154373 ccb->pkt_dma_offset = 0; 12946008Syy154373 ccb->resid_dmacookie.dmac_size = 0; 12956008Syy154373 12966008Syy154373 /* 12976008Syy154373 * we will still use this point for we want to fake some 12986008Syy154373 * information in tran_start 12996008Syy154373 */ 13006008Syy154373 ccb->bp = bp; 13016008Syy154373 13026008Syy154373 /* Initialize arcmsr_cdb */ 13036008Syy154373 arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; 13046008Syy154373 bzero(arcmsr_cdb, sizeof (struct ARCMSR_CDB)); 13056008Syy154373 arcmsr_cdb->Bus = 0; 13066008Syy154373 arcmsr_cdb->Function = 1; 13076008Syy154373 arcmsr_cdb->LUN = ap->a_lun; 13086008Syy154373 arcmsr_cdb->TargetID = ap->a_target; 13096008Syy154373 arcmsr_cdb->CdbLength = (uint8_t)cmdlen; 13106008Syy154373 arcmsr_cdb->Context = (unsigned long)arcmsr_cdb; 13116008Syy154373 13126008Syy154373 /* Fill in the rest of the structure */ 13136008Syy154373 pkt->pkt_ha_private = ccb; 13146008Syy154373 pkt->pkt_address = *ap; 13156008Syy154373 pkt->pkt_comp = (void (*)())NULL; 13166008Syy154373 pkt->pkt_flags = 0; 13176008Syy154373 pkt->pkt_time = 0; 13186008Syy154373 pkt->pkt_resid = 0; 13196008Syy154373 pkt->pkt_statistics = 0; 13206008Syy154373 pkt->pkt_reason = 0; 13216008Syy154373 old_pkt_flag = 0; 13226008Syy154373 } else { 13236008Syy154373 ccb = (struct CCB *)pkt->pkt_ha_private; 13246008Syy154373 /* 13256008Syy154373 * you cannot update CdbLength with cmdlen here, it would 13266008Syy154373 * cause a data compare error 13276008Syy154373 */ 13286008Syy154373 ccb->startdone = ARCMSR_CCB_UNBUILD; 13296008Syy154373 } 13306008Syy154373 13316008Syy154373 /* Second step : dma allocation/move */ 13326008Syy154373 if (bp && bp->b_bcount != 0) { 13336008Syy154373 /* 13346008Syy154373 * system had a lot of data trunk need to xfer, from...20 byte 13356008Syy154373 * to 819200 byte. 13366008Syy154373 * arcmsr_dma_alloc will get pkt_dma_handle (not null) until 13376008Syy154373 * this lot of data trunk xfer done this mission will be done 13386008Syy154373 * by some of continue READ or WRITE scsi command, till this 13396008Syy154373 * lot of data trunk xfer completed. 13406008Syy154373 * arcmsr_dma_move do the action repeatedly, and use the same 13416008Syy154373 * ccb till this lot of data trunk xfer complete notice. 13426008Syy154373 * when after the arcmsr_tran_init_pkt returns the solaris 13436008Syy154373 * kernel is by your pkt_resid and its b_bcount to give you 13446008Syy154373 * which type of scsi command descriptor to implement the 13456008Syy154373 * length of folowing arcmsr_tran_start scsi cdb (data length) 13466008Syy154373 * 13476008Syy154373 * Each transfer should be aligned on a 512 byte boundary 13486008Syy154373 */ 13496008Syy154373 if (ccb->pkt_dma_handle == NULL) { 13506008Syy154373 if (arcmsr_dma_alloc(acb, pkt, bp, flags, 13516008Syy154373 callback) == DDI_FAILURE) { 13526008Syy154373 /* 13536008Syy154373 * the HBA driver is unable to allocate DMA 13546008Syy154373 * resources, it must free the allocated 13556008Syy154373 * scsi_pkt(9S) before returning 13566008Syy154373 */ 13576008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma allocation " 13586008Syy154373 "failure ", 13596008Syy154373 ddi_get_instance(acb->dev_info)); 13606008Syy154373 if (old_pkt_flag == 0) { 13616008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma " 13626008Syy154373 "allocation failed to free scsi " 13636008Syy154373 "hba pkt ", 13646008Syy154373 ddi_get_instance(acb->dev_info)); 13656008Syy154373 arcmsr_free_ccb(ccb); 13666008Syy154373 scsi_hba_pkt_free(ap, pkt); 13676008Syy154373 } 13686008Syy154373 return ((struct scsi_pkt *)NULL); 13696008Syy154373 } 13706008Syy154373 } else { 13716008Syy154373 /* DMA resources to next DMA window, for old pkt */ 13726008Syy154373 if (arcmsr_dma_move(acb, pkt, bp) == -1) { 13736008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma move " 13746008Syy154373 "failed ", 13756008Syy154373 ddi_get_instance(acb->dev_info)); 13766008Syy154373 return ((struct scsi_pkt *)NULL); 13776008Syy154373 } 13786008Syy154373 } 13796008Syy154373 } else { 13806008Syy154373 pkt->pkt_resid = 0; 13816008Syy154373 } 13826008Syy154373 return (pkt); 13836008Syy154373} 13846008Syy154373 13856008Syy154373/* 13866008Syy154373 * Function name: arcmsr_dma_alloc 13876008Syy154373 * Return Values: 0 if successful, -1 if failure 13886008Syy154373 * Description: allocate DMA resources 13896008Syy154373 * Context: Can only be called from arcmsr_tran_init_pkt() 13906008Syy154373 * register struct scsi_address *ap = &((pkt)->pkt_address); 13916008Syy154373 */ 13926008Syy154373static int 13936008Syy154373arcmsr_dma_alloc(struct ACB *acb, struct scsi_pkt *pkt, 13946008Syy154373 struct buf *bp, int flags, int (*callback)()) { 13956008Syy154373 13966008Syy154373 struct CCB *ccb = pkt->pkt_ha_private; 13976008Syy154373 int alloc_result, map_method, dma_flags; 13986008Syy154373 int resid = 0; 13996008Syy154373 int total_ccb_xferlen = 0; 14006008Syy154373 int (*cb)(caddr_t); 14016008Syy154373 uint8_t i; 14026008Syy154373 14036008Syy154373 /* 14046008Syy154373 * at this point the PKT SCSI CDB is empty, and dma xfer length 14056008Syy154373 * is bp->b_bcount 14066008Syy154373 */ 14076008Syy154373 14086008Syy154373 if (bp->b_flags & B_READ) { 14096008Syy154373 ccb->ccb_flags &= ~CCB_FLAG_DMAWRITE; 14106008Syy154373 dma_flags = DDI_DMA_READ; 14116008Syy154373 } else { 14126008Syy154373 ccb->ccb_flags |= CCB_FLAG_DMAWRITE; 14136008Syy154373 dma_flags = DDI_DMA_WRITE; 14146008Syy154373 } 14156008Syy154373 14166008Syy154373 if (flags & PKT_CONSISTENT) { 14176008Syy154373 ccb->ccb_flags |= CCB_FLAG_DMACONSISTENT; 14186008Syy154373 dma_flags |= DDI_DMA_CONSISTENT; 14196008Syy154373 } 14206008Syy154373 if (flags & PKT_DMA_PARTIAL) { 14216008Syy154373 dma_flags |= DDI_DMA_PARTIAL; 14226008Syy154373 } 14236008Syy154373 14246008Syy154373 dma_flags |= DDI_DMA_REDZONE; 14256008Syy154373 cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP; 14266008Syy154373 14276008Syy154373 if ((alloc_result = ddi_dma_alloc_handle(acb->dev_info, 14286008Syy154373 &arcmsr_dma_attr, cb, 0, &ccb->pkt_dma_handle)) 14296008Syy154373 != DDI_SUCCESS) { 14306008Syy154373 switch (alloc_result) { 14316008Syy154373 case DDI_DMA_BADATTR: 14326008Syy154373 /* 14336008Syy154373 * If the system does not support physical DMA, 14346008Syy154373 * the return value from ddi_dma_alloc_handle 14356008Syy154373 * will be DDI_DMA_BADATTR 14366008Syy154373 */ 14376008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma allocate returned " 14386008Syy154373 "'bad attribute'", 14396008Syy154373 ddi_get_instance(acb->dev_info)); 14406008Syy154373 bioerror(bp, EFAULT); 14416008Syy154373 return (DDI_FAILURE); 14426008Syy154373 case DDI_DMA_NORESOURCES: 14436008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma allocate returned " 14446008Syy154373 "'no resources'", 14456008Syy154373 ddi_get_instance(acb->dev_info)); 14466008Syy154373 bioerror(bp, 0); 14476008Syy154373 return (DDI_FAILURE); 14486008Syy154373 default: 14496008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma allocate returned " 14506008Syy154373 "'unknown failure'", 14516008Syy154373 ddi_get_instance(acb->dev_info)); 14526008Syy154373 return (DDI_FAILURE); 14536008Syy154373 } 14546008Syy154373 } 14556008Syy154373 14566008Syy154373 map_method = ddi_dma_buf_bind_handle(ccb->pkt_dma_handle, bp, 14576008Syy154373 dma_flags, cb, 0, 14586008Syy154373 &ccb->pkt_dmacookies[0], /* SG List pointer */ 14596008Syy154373 &ccb->pkt_ncookies); /* number of sgl cookies */ 14606008Syy154373 14616008Syy154373 switch (map_method) { 14626008Syy154373 case DDI_DMA_PARTIAL_MAP: 14636008Syy154373 /* 14646008Syy154373 * When your main memory size larger then 4G 14656008Syy154373 * DDI_DMA_PARTIAL_MAP will be touched. 14666008Syy154373 * 14676008Syy154373 * We've already set DDI_DMA_PARTIAL in dma_flags, 14686008Syy154373 * so if it's now missing, there's something screwy 14696008Syy154373 * happening. We plow on.... 14706008Syy154373 */ 14716008Syy154373 14726008Syy154373 if ((dma_flags & DDI_DMA_PARTIAL) == 0) { 14736008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma partial mapping lost " 14746008Syy154373 "...impossible case!", 14756008Syy154373 ddi_get_instance(acb->dev_info)); 14766008Syy154373 } 14776008Syy154373 if (ddi_dma_numwin(ccb->pkt_dma_handle, &ccb->pkt_nwin) == 14786008Syy154373 DDI_FAILURE) { 14796008Syy154373 cmn_err(CE_WARN, "arcmsr%d: ddi_dma_numwin() failed", 14806008Syy154373 ddi_get_instance(acb->dev_info)); 14816008Syy154373 } 14826008Syy154373 14836008Syy154373 if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin, 14846008Syy154373 &ccb->pkt_dma_offset, &ccb->pkt_dma_len, 14856008Syy154373 &ccb->pkt_dmacookies[0], &ccb->pkt_ncookies) == 14866008Syy154373 DDI_FAILURE) { 14876008Syy154373 cmn_err(CE_WARN, "arcmsr%d: ddi_dma_getwin failed", 14886008Syy154373 ddi_get_instance(acb->dev_info)); 14896008Syy154373 } 14906008Syy154373 14916008Syy154373 i = 0; 14926008Syy154373 /* first cookie is accessed from ccb->pkt_dmacookies[0] */ 14936008Syy154373 total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size; 14946008Syy154373 for (;;) { 14956008Syy154373 i++; 14966008Syy154373 if (i == ARCMSR_MAX_SG_ENTRIES || 14976008Syy154373 i == ccb->pkt_ncookies || 14986008Syy154373 total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) { 14996008Syy154373 break; 15006008Syy154373 } 15016008Syy154373 /* 15026008Syy154373 * next cookie will be retrieved from 15036008Syy154373 * ccb->pkt_dmacookies[i] 15046008Syy154373 */ 15056008Syy154373 ddi_dma_nextcookie(ccb->pkt_dma_handle, 15066008Syy154373 &ccb->pkt_dmacookies[i]); 15076008Syy154373 total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size; 15086008Syy154373 } 15096008Syy154373 ccb->pkt_cookie = i; 15106008Syy154373 ccb->arcmsr_cdb.sgcount = i; 15116008Syy154373 if (total_ccb_xferlen > 512) { 15126008Syy154373 resid = total_ccb_xferlen % 512; 15136008Syy154373 if (resid != 0) { 15146008Syy154373 i--; 15156008Syy154373 total_ccb_xferlen -= resid; 15166008Syy154373 /* modify last sg length */ 15176008Syy154373 ccb->pkt_dmacookies[i].dmac_size = 15186008Syy154373 ccb->pkt_dmacookies[i].dmac_size - resid; 15196008Syy154373 ccb->resid_dmacookie.dmac_size = resid; 15206008Syy154373 ccb->resid_dmacookie.dmac_laddress = 15216008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress + 15226008Syy154373 ccb->pkt_dmacookies[i].dmac_size; 15236008Syy154373 } 15246008Syy154373 } 15256008Syy154373 ccb->total_dmac_size = total_ccb_xferlen; 15266008Syy154373 ccb->ccb_flags |= CCB_FLAG_DMAVALID; 15276008Syy154373 pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size; 15286008Syy154373 15296008Syy154373 return (DDI_SUCCESS); 15306008Syy154373 15316008Syy154373 case DDI_DMA_MAPPED: 15326008Syy154373 ccb->pkt_nwin = 1; /* all mapped, so only one window */ 15336008Syy154373 ccb->pkt_dma_len = 0; 15346008Syy154373 ccb->pkt_dma_offset = 0; 15356008Syy154373 i = 0; 15366008Syy154373 /* first cookie is accessed from ccb->pkt_dmacookies[0] */ 15376008Syy154373 total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size; 15386008Syy154373 for (;;) { 15396008Syy154373 i++; 15406008Syy154373 if (i == ARCMSR_MAX_SG_ENTRIES || 15416008Syy154373 i == ccb->pkt_ncookies || 15426008Syy154373 total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) { 15436008Syy154373 break; 15446008Syy154373 } 15456008Syy154373 /* 15466008Syy154373 * next cookie will be retrieved from 15476008Syy154373 * ccb->pkt_dmacookies[i] 15486008Syy154373 */ 15496008Syy154373 ddi_dma_nextcookie(ccb->pkt_dma_handle, 15506008Syy154373 &ccb->pkt_dmacookies[i]); 15516008Syy154373 total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size; 15526008Syy154373 } 15536008Syy154373 ccb->pkt_cookie = i; 15546008Syy154373 ccb->arcmsr_cdb.sgcount = i; 15556008Syy154373 if (total_ccb_xferlen > 512) { 15566008Syy154373 resid = total_ccb_xferlen % 512; 15576008Syy154373 if (resid != 0) { 15586008Syy154373 i--; 15596008Syy154373 total_ccb_xferlen -= resid; 15606008Syy154373 /* modify last sg length */ 15616008Syy154373 ccb->pkt_dmacookies[i].dmac_size = 15626008Syy154373 ccb->pkt_dmacookies[i].dmac_size - resid; 15636008Syy154373 ccb->resid_dmacookie.dmac_size = resid; 15646008Syy154373 ccb->resid_dmacookie.dmac_laddress = 15656008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress + 15666008Syy154373 ccb->pkt_dmacookies[i].dmac_size; 15676008Syy154373 } 15686008Syy154373 } 15696008Syy154373 ccb->total_dmac_size = total_ccb_xferlen; 15706008Syy154373 ccb->ccb_flags |= CCB_FLAG_DMAVALID; 15716008Syy154373 pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size; 15726008Syy154373 return (DDI_SUCCESS); 15736008Syy154373 15746008Syy154373 case DDI_DMA_NORESOURCES: 15756008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma map got 'no resources'", 15766008Syy154373 ddi_get_instance(acb->dev_info)); 15776008Syy154373 bioerror(bp, ENOMEM); 15786008Syy154373 break; 15796008Syy154373 15806008Syy154373 case DDI_DMA_NOMAPPING: 15816008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma map got 'no mapping'", 15826008Syy154373 ddi_get_instance(acb->dev_info)); 15836008Syy154373 bioerror(bp, EFAULT); 15846008Syy154373 break; 15856008Syy154373 15866008Syy154373 case DDI_DMA_TOOBIG: 15876008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma map got 'too big'", 15886008Syy154373 ddi_get_instance(acb->dev_info)); 15896008Syy154373 bioerror(bp, EINVAL); 15906008Syy154373 break; 15916008Syy154373 15926008Syy154373 case DDI_DMA_INUSE: 15936008Syy154373 cmn_err(CE_WARN, "arcmsr%d: dma map got 'in use' " 15946008Syy154373 "(should not happen)", 15956008Syy154373 ddi_get_instance(acb->dev_info)); 15966008Syy154373 break; 15976008Syy154373 default: 15986008Syy154373 cmn_err(CE_WARN, 15996008Syy154373 "arcmsr%d: dma map got 'unknown failure 0x%x' " 16006008Syy154373 "(should not happen)", 16016008Syy154373 ddi_get_instance(acb->dev_info), i); 16026008Syy154373#ifdef ARCMSR_DEBUG 16036008Syy154373 arcmsr_dump_scsi_cdb(&pkt->pkt_address, pkt); 16046008Syy154373#endif 16056008Syy154373 break; 16066008Syy154373 } 16076008Syy154373 16086008Syy154373 ddi_dma_free_handle(&ccb->pkt_dma_handle); 16096008Syy154373 ccb->pkt_dma_handle = NULL; 16106008Syy154373 ccb->ccb_flags &= ~CCB_FLAG_DMAVALID; 16116008Syy154373 return (DDI_FAILURE); 16126008Syy154373} 16136008Syy154373 16146008Syy154373 16156008Syy154373/* 16166008Syy154373 * Function name: arcmsr_dma_move 16176008Syy154373 * Return Values: 0 if successful, -1 if failure 16186008Syy154373 * Description: move DMA resources to next DMA window 16196008Syy154373 * Context: Can only be called from arcmsr_tran_init_pkt() 16206008Syy154373 */ 16216008Syy154373static int 16226008Syy154373arcmsr_dma_move(struct ACB *acb, struct scsi_pkt *pkt, 16236008Syy154373 struct buf *bp) { 16246008Syy154373 16256008Syy154373 struct CCB *ccb = pkt->pkt_ha_private; 16266008Syy154373 uint8_t i = 0; 16276008Syy154373 int resid = 0; 16286008Syy154373 int total_ccb_xferlen = 0; 16296008Syy154373 16306008Syy154373 if (ccb->resid_dmacookie.dmac_size != 0) { 16316008Syy154373 total_ccb_xferlen += ccb->resid_dmacookie.dmac_size; 16326008Syy154373 ccb->pkt_dmacookies[i].dmac_size = 16336008Syy154373 ccb->resid_dmacookie.dmac_size; 16346008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress = 16356008Syy154373 ccb->resid_dmacookie.dmac_laddress; 16366008Syy154373 i++; 16376008Syy154373 ccb->resid_dmacookie.dmac_size = 0; 16386008Syy154373 } 16396008Syy154373 /* 16406008Syy154373 * If there are no more cookies remaining in this window, 16416008Syy154373 * move to the next window. 16426008Syy154373 */ 16436008Syy154373 if (ccb->pkt_cookie == ccb->pkt_ncookies) { 16446008Syy154373 /* 16456008Syy154373 * only dma map "partial" arrive here 16466008Syy154373 */ 16476008Syy154373 if ((ccb->pkt_curwin == ccb->pkt_nwin) && 16486008Syy154373 (ccb->pkt_nwin == 1)) { 16496008Syy154373 cmn_err(CE_CONT, 16506008Syy154373 "arcmsr%d: dma partial set, but only " 16516008Syy154373 "one window allocated", 16526008Syy154373 ddi_get_instance(acb->dev_info)); 16536008Syy154373 return (DDI_SUCCESS); 16546008Syy154373 } 16556008Syy154373 16566008Syy154373 /* At last window, cannot move */ 16576008Syy154373 if (++ccb->pkt_curwin >= ccb->pkt_nwin) { 16586008Syy154373 cmn_err(CE_WARN, 16596008Syy154373 "arcmsr%d: dma partial set, numwin exceeded", 16606008Syy154373 ddi_get_instance(acb->dev_info)); 16616008Syy154373 return (DDI_FAILURE); 16626008Syy154373 } 16636008Syy154373 if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin, 16646008Syy154373 &ccb->pkt_dma_offset, &ccb->pkt_dma_len, 16656008Syy154373 &ccb->pkt_dmacookies[i], &ccb->pkt_ncookies) == 16666008Syy154373 DDI_FAILURE) { 16676008Syy154373 cmn_err(CE_WARN, 16686008Syy154373 "arcmsr%d: dma partial set, " 16696008Syy154373 "ddi_dma_getwin failure", 16706008Syy154373 ddi_get_instance(acb->dev_info)); 16716008Syy154373 return (DDI_FAILURE); 16726008Syy154373 } 16736008Syy154373 /* reset cookie pointer */ 16746008Syy154373 ccb->pkt_cookie = 0; 16756008Syy154373 } else { 16766008Syy154373 /* 16776008Syy154373 * only dma map "all" arrive here 16786008Syy154373 * We still have more cookies in this window, 16796008Syy154373 * get the next one 16806008Syy154373 * access the pkt_dma_handle remain cookie record at 16816008Syy154373 * ccb->pkt_dmacookies array 16826008Syy154373 */ 16836008Syy154373 ddi_dma_nextcookie(ccb->pkt_dma_handle, 16846008Syy154373 &ccb->pkt_dmacookies[i]); 16856008Syy154373 } 16866008Syy154373 16876008Syy154373 /* Get remaining cookies in this window, up to our maximum */ 16886008Syy154373 total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size; 16896008Syy154373 16906008Syy154373 /* retrieve and store cookies, start at ccb->pkt_dmacookies[0] */ 16916008Syy154373 for (;;) { 16926008Syy154373 i++; 16936008Syy154373 /* handled cookies count level indicator */ 16946008Syy154373 ccb->pkt_cookie++; 16956008Syy154373 if (i == ARCMSR_MAX_SG_ENTRIES || 16966008Syy154373 ccb->pkt_cookie == ccb->pkt_ncookies || 16976008Syy154373 total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) { 16986008Syy154373 break; 16996008Syy154373 } 17006008Syy154373 ddi_dma_nextcookie(ccb->pkt_dma_handle, 17016008Syy154373 &ccb->pkt_dmacookies[i]); 17026008Syy154373 total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size; 17036008Syy154373 } 17046008Syy154373 17056008Syy154373 ccb->arcmsr_cdb.sgcount = i; 17066008Syy154373 if (total_ccb_xferlen > 512) { 17076008Syy154373 resid = total_ccb_xferlen % 512; 17086008Syy154373 if (resid != 0) { 17096008Syy154373 i--; 17106008Syy154373 total_ccb_xferlen -= resid; 17116008Syy154373 /* modify last sg length */ 17126008Syy154373 ccb->pkt_dmacookies[i].dmac_size = 17136008Syy154373 ccb->pkt_dmacookies[i].dmac_size - resid; 17146008Syy154373 ccb->resid_dmacookie.dmac_size = resid; 17156008Syy154373 ccb->resid_dmacookie.dmac_laddress = 17166008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress + 17176008Syy154373 ccb->pkt_dmacookies[i].dmac_size; 17186008Syy154373 } 17196008Syy154373 } 17206008Syy154373 ccb->total_dmac_size += total_ccb_xferlen; 17216008Syy154373 pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size; 17226008Syy154373 17236008Syy154373 return (DDI_SUCCESS); 17246008Syy154373} 17256008Syy154373 17266008Syy154373/* 17276008Syy154373 * Function name: arcmsr_tran_destroy_pkt 17286008Syy154373 * Return Values: none 17296008Syy154373 * Description: Called by kernel on behalf of a target driver 17306008Syy154373 * calling scsi_destroy_pkt(9F). 17316008Syy154373 * Refer to tran_destroy_pkt(9E) man page 17326008Syy154373 * Context: Can be called from different kernel process threads. 17336008Syy154373 * Can be called by interrupt thread. 17346008Syy154373 */ 17356008Syy154373static void 17366008Syy154373arcmsr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) { 17376008Syy154373 17386008Syy154373 struct CCB *ccb = pkt->pkt_ha_private; 17396008Syy154373 17406008Syy154373 if ((ccb != NULL) && (ccb->pkt == pkt)) { 17416008Syy154373 struct ACB *acb = ccb->acb; 17426008Syy154373 if (ccb->ccb_flags & CCB_FLAG_DMAVALID) { 17436008Syy154373 if (ddi_dma_unbind_handle(ccb->pkt_dma_handle) 17446008Syy154373 != DDI_SUCCESS) { 17456008Syy154373 cmn_err(CE_WARN, 17466008Syy154373 "arcmsr%d: ddi_dma_unbind_handle() failed", 17476008Syy154373 ddi_get_instance(acb->dev_info)); 17486008Syy154373 } 17496008Syy154373 ddi_dma_free_handle(&ccb->pkt_dma_handle); 17506008Syy154373 ccb->pkt_dma_handle = NULL; 17516008Syy154373 } 17526008Syy154373 arcmsr_free_ccb(ccb); 17536008Syy154373 } 17546008Syy154373 17556008Syy154373 scsi_hba_pkt_free(ap, pkt); 17566008Syy154373} 17576008Syy154373 17586008Syy154373/* 17596008Syy154373 * Function name: arcmsr_tran_dmafree() 17606008Syy154373 * Return Values: none 17616008Syy154373 * Description: free dvma resources 17626008Syy154373 * Context: Can be called from different kernel process threads. 17636008Syy154373 * Can be called by interrupt thread. 17646008Syy154373 */ 17656008Syy154373static void 17666008Syy154373arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) { 17676008Syy154373 17686008Syy154373 struct CCB *ccb = pkt->pkt_ha_private; 17696008Syy154373 17706008Syy154373 if (ccb->ccb_flags & CCB_FLAG_DMAVALID) { 17716008Syy154373 ccb->ccb_flags &= ~CCB_FLAG_DMAVALID; 17726008Syy154373 if (ddi_dma_unbind_handle(ccb->pkt_dma_handle) 17736008Syy154373 != DDI_SUCCESS) { 17746008Syy154373 cmn_err(CE_WARN, 17756008Syy154373 "arcmsr%d: ddi_dma_unbind_handle() failed " 17766008Syy154373 "(target %d lun %d)", 17776008Syy154373 ddi_get_instance(ccb->acb->dev_info), 17786008Syy154373 ap->a_target, ap->a_lun); 17796008Syy154373 } 17806008Syy154373 ddi_dma_free_handle(&ccb->pkt_dma_handle); 17816008Syy154373 ccb->pkt_dma_handle = NULL; 17826008Syy154373 } 17836008Syy154373} 17846008Syy154373 17856008Syy154373/* 17866008Syy154373 * Function name: arcmsr_tran_sync_pkt() 17876008Syy154373 * Return Values: none 17886008Syy154373 * Description: sync dma 17896008Syy154373 * Context: Can be called from different kernel process threads. 17906008Syy154373 * Can be called by interrupt thread. 17916008Syy154373 */ 17926008Syy154373static void 17936008Syy154373arcmsr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) { 17946008Syy154373 17956008Syy154373 struct CCB *ccb; 17966008Syy154373 17976008Syy154373 ccb = pkt->pkt_ha_private; 17986008Syy154373 17996008Syy154373 if (ccb->ccb_flags & CCB_FLAG_DMAVALID) { 18006008Syy154373 if (ddi_dma_sync(ccb->pkt_dma_handle, 18016008Syy154373 ccb->pkt_dma_offset, ccb->pkt_dma_len, 18026008Syy154373 (ccb->ccb_flags & CCB_FLAG_DMAWRITE) ? 18036008Syy154373 DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU) 18046008Syy154373 != DDI_SUCCESS) { 18056008Syy154373 cmn_err(CE_WARN, "arcmsr%d: sync pkt failed " 18066008Syy154373 "for target %d lun %d", 18076008Syy154373 ddi_get_instance(ccb->acb->dev_info), 18086008Syy154373 ap->a_target, ap->a_lun); 18096008Syy154373 } 18106008Syy154373 } 18116008Syy154373} 18126008Syy154373 18136008Syy154373 18146008Syy154373static uint8_t 18156008Syy154373arcmsr_hba_wait_msgint_ready(struct ACB *acb) { 18166008Syy154373 18176008Syy154373 uint32_t i; 18186008Syy154373 uint8_t retries = 0x00; 18196008Syy154373 struct HBA_msgUnit *phbamu; 18206008Syy154373 18216008Syy154373 18226008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 18236008Syy154373 18246008Syy154373 do { 18256008Syy154373 for (i = 0; i < 100; i++) { 18266008Syy154373 if (CHIP_REG_READ32(acb->reg_mu_acc_handle0, 18276008Syy154373 &phbamu->outbound_intstatus) & 18286008Syy154373 ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { 18296008Syy154373 /* clear interrupt */ 18306008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18316008Syy154373 &phbamu->outbound_intstatus, 18326008Syy154373 ARCMSR_MU_OUTBOUND_MESSAGE0_INT); 18336008Syy154373 return (TRUE); 18346008Syy154373 } 18356008Syy154373 drv_usecwait(10000); 18366008Syy154373 if (ddi_in_panic()) { 18376008Syy154373 /* clear interrupts */ 18386008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18396008Syy154373 &phbamu->outbound_intstatus, 18406008Syy154373 ARCMSR_MU_OUTBOUND_MESSAGE0_INT); 18416008Syy154373 return (TRUE); 18426008Syy154373 } 18436008Syy154373 } /* max 1 second */ 18446008Syy154373 } while (retries++ < 20); /* max 20 seconds */ 18456008Syy154373 return (FALSE); 18466008Syy154373} 18476008Syy154373 18486008Syy154373 18496008Syy154373 18506008Syy154373static uint8_t 18516008Syy154373arcmsr_hbb_wait_msgint_ready(struct ACB *acb) { 18526008Syy154373 18536008Syy154373 struct HBB_msgUnit *phbbmu; 18546008Syy154373 uint32_t i; 18556008Syy154373 uint8_t retries = 0x00; 18566008Syy154373 18576008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 18586008Syy154373 18596008Syy154373 do { 18606008Syy154373 for (i = 0; i < 100; i++) { 18616008Syy154373 if (CHIP_REG_READ32(acb->reg_mu_acc_handle0, 18626008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell) & 18636008Syy154373 ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { 18646008Syy154373 /* clear interrupt */ 18656008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18666008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 18676008Syy154373 ARCMSR_MESSAGE_INT_CLEAR_PATTERN); 18686008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18696008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 18706008Syy154373 ARCMSR_DRV2IOP_END_OF_INTERRUPT); 18716008Syy154373 return (TRUE); 18726008Syy154373 } 18736008Syy154373 drv_usecwait(10000); 18746008Syy154373 if (ddi_in_panic()) { 18756008Syy154373 /* clear interrupts */ 18766008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18776008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 18786008Syy154373 ARCMSR_MESSAGE_INT_CLEAR_PATTERN); 18796008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 18806008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 18816008Syy154373 ARCMSR_DRV2IOP_END_OF_INTERRUPT); 18826008Syy154373 return (TRUE); 18836008Syy154373 } 18846008Syy154373 } /* max 1 second */ 18856008Syy154373 } while (retries++ < 20); /* max 20 seconds */ 18866008Syy154373 18876008Syy154373 return (FALSE); 18886008Syy154373} 18896008Syy154373 18906008Syy154373 18916008Syy154373static void 18926008Syy154373arcmsr_flush_hba_cache(struct ACB *acb) { 18936008Syy154373 18946008Syy154373 struct HBA_msgUnit *phbamu; 18956008Syy154373 int retry_count = 30; 18966008Syy154373 18976008Syy154373 /* enlarge wait flush adapter cache time: 10 minutes */ 18986008Syy154373 18996008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 19006008Syy154373 19016008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0, 19026008Syy154373 ARCMSR_INBOUND_MESG0_FLUSH_CACHE); 19036008Syy154373 19046008Syy154373 do { 19056008Syy154373 if (arcmsr_hba_wait_msgint_ready(acb)) { 19066008Syy154373 break; 19076008Syy154373 } else { 19086008Syy154373 retry_count--; 19096008Syy154373 } 19106008Syy154373 } while (retry_count != 0); 19116008Syy154373} 19126008Syy154373 19136008Syy154373 19146008Syy154373 19156008Syy154373static void 19166008Syy154373arcmsr_flush_hbb_cache(struct ACB *acb) { 19176008Syy154373 19186008Syy154373 struct HBB_msgUnit *phbbmu; 19196008Syy154373 int retry_count = 30; 19206008Syy154373 19216008Syy154373 /* enlarge wait flush adapter cache time: 10 minutes */ 19226008Syy154373 19236008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 19246008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 19256008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 19266008Syy154373 ARCMSR_MESSAGE_FLUSH_CACHE); 19276008Syy154373 19286008Syy154373 do { 19296008Syy154373 if (arcmsr_hbb_wait_msgint_ready(acb)) { 19306008Syy154373 break; 19316008Syy154373 } else { 19326008Syy154373 retry_count--; 19336008Syy154373 } 19346008Syy154373 } while (retry_count != 0); 19356008Syy154373} 19366008Syy154373 19376008Syy154373 19386008Syy154373static void 19396008Syy154373arcmsr_ccb_complete(struct CCB *ccb, int flag) { 19406008Syy154373 19416008Syy154373 struct ACB *acb = ccb->acb; 19426008Syy154373 struct scsi_pkt *pkt = ccb->pkt; 19436008Syy154373 19446008Syy154373 if (flag == 1) { 19456008Syy154373 atomic_add_32((volatile uint32_t *) 19466008Syy154373 &acb->ccboutstandingcount, -1); 19476008Syy154373 } 19486008Syy154373 pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | 19496008Syy154373 STATE_SENT_CMD | STATE_GOT_STATUS); 19506008Syy154373 19516008Syy154373 if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) && 19526008Syy154373 (pkt->pkt_state & STATE_XFERRED_DATA)) { 19536008Syy154373 (void) ddi_dma_sync(ccb->pkt_dma_handle, 19546008Syy154373 ccb->pkt_dma_offset, ccb->pkt_dma_len, 19556008Syy154373 DDI_DMA_SYNC_FORCPU); 19566008Syy154373 } 19576008Syy154373 19586008Syy154373 scsi_hba_pkt_comp(pkt); 19596008Syy154373} 19606008Syy154373 19616008Syy154373 19626008Syy154373static void 19636008Syy154373arcmsr_report_sense_info(struct CCB *ccb) { 19646008Syy154373 19656008Syy154373 struct scsi_pkt *pkt = ccb->pkt; 19666008Syy154373 struct scsi_arq_status *arq_status; 19676008Syy154373 19686008Syy154373 19696008Syy154373 arq_status = (struct scsi_arq_status *)(intptr_t)(pkt->pkt_scbp); 19706008Syy154373 bzero((caddr_t)arq_status, sizeof (struct scsi_arq_status)); 19716008Syy154373 arq_status->sts_rqpkt_reason = CMD_CMPLT; 19726008Syy154373 arq_status->sts_rqpkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET | 19736008Syy154373 STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS); 19746008Syy154373 arq_status->sts_rqpkt_statistics = pkt->pkt_statistics; 19756008Syy154373 arq_status->sts_rqpkt_resid = 0; 19766008Syy154373 19776008Syy154373 pkt->pkt_reason = CMD_CMPLT; 19786008Syy154373 /* auto rqsense took place */ 19796008Syy154373 pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | 19806008Syy154373 STATE_GOT_STATUS | STATE_ARQ_DONE); 19816008Syy154373 19826008Syy154373 if (&arq_status->sts_sensedata != NULL) { 19836008Syy154373 struct SENSE_DATA *cdb_sensedata; 19846008Syy154373 struct scsi_extended_sense *sts_sensedata; 19856008Syy154373 19866008Syy154373 cdb_sensedata = 19876008Syy154373 (struct SENSE_DATA *)ccb->arcmsr_cdb.SenseData; 19886008Syy154373 sts_sensedata = &arq_status->sts_sensedata; 19896008Syy154373 19906008Syy154373 sts_sensedata->es_code = cdb_sensedata->ErrorCode; 19916008Syy154373 /* must eq CLASS_EXTENDED_SENSE (0x07) */ 19926008Syy154373 sts_sensedata->es_class = cdb_sensedata->ErrorClass; 19936008Syy154373 sts_sensedata->es_valid = cdb_sensedata->Valid; 19946008Syy154373 sts_sensedata->es_segnum = cdb_sensedata->SegmentNumber; 19956008Syy154373 sts_sensedata->es_key = cdb_sensedata->SenseKey; 19966008Syy154373 sts_sensedata->es_ili = cdb_sensedata->IncorrectLength; 19976008Syy154373 sts_sensedata->es_eom = cdb_sensedata->EndOfMedia; 19986008Syy154373 sts_sensedata->es_filmk = cdb_sensedata->FileMark; 19996008Syy154373 sts_sensedata->es_info_1 = cdb_sensedata->Information[0]; 20006008Syy154373 sts_sensedata->es_info_2 = cdb_sensedata->Information[1]; 20016008Syy154373 sts_sensedata->es_info_3 = cdb_sensedata->Information[2]; 20026008Syy154373 sts_sensedata->es_info_4 = cdb_sensedata->Information[3]; 20036008Syy154373 sts_sensedata->es_add_len = 20046008Syy154373 cdb_sensedata->AdditionalSenseLength; 20056008Syy154373 sts_sensedata->es_cmd_info[0] = 20066008Syy154373 cdb_sensedata->CommandSpecificInformation[0]; 20076008Syy154373 sts_sensedata->es_cmd_info[1] = 20086008Syy154373 cdb_sensedata->CommandSpecificInformation[1]; 20096008Syy154373 sts_sensedata->es_cmd_info[2] = 20106008Syy154373 cdb_sensedata->CommandSpecificInformation[2]; 20116008Syy154373 sts_sensedata->es_cmd_info[3] = 20126008Syy154373 cdb_sensedata->CommandSpecificInformation[3]; 20136008Syy154373 sts_sensedata->es_add_code = 20146008Syy154373 cdb_sensedata->AdditionalSenseCode; 20156008Syy154373 sts_sensedata->es_qual_code = 20166008Syy154373 cdb_sensedata->AdditionalSenseCodeQualifier; 20176008Syy154373 sts_sensedata->es_fru_code = 20186008Syy154373 cdb_sensedata->FieldReplaceableUnitCode; 20196008Syy154373 } 20206008Syy154373} 20216008Syy154373 20226008Syy154373 20236008Syy154373 20246008Syy154373static void 20256008Syy154373arcmsr_abort_hba_allcmd(struct ACB *acb) { 20266008Syy154373 20276008Syy154373 struct HBA_msgUnit *phbamu; 20286008Syy154373 20296008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 20306008Syy154373 20316008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 20326008Syy154373 &phbamu->inbound_msgaddr0, 20336008Syy154373 ARCMSR_INBOUND_MESG0_ABORT_CMD); 20346008Syy154373 20356008Syy154373 if (!arcmsr_hba_wait_msgint_ready(acb)) { 20366008Syy154373 cmn_err(CE_WARN, 20376008Syy154373 "arcmsr%d: timeout while waiting for 'abort all " 20386008Syy154373 "outstanding commands'", 20396008Syy154373 ddi_get_instance(acb->dev_info)); 20406008Syy154373 } 20416008Syy154373} 20426008Syy154373 20436008Syy154373 20446008Syy154373 20456008Syy154373static void 20466008Syy154373arcmsr_abort_hbb_allcmd(struct ACB *acb) { 20476008Syy154373 20486008Syy154373 struct HBB_msgUnit *phbbmu = 20496008Syy154373 (struct HBB_msgUnit *)acb->pmu; 20506008Syy154373 20516008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 20526008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 20536008Syy154373 ARCMSR_MESSAGE_ABORT_CMD); 20546008Syy154373 20556008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) { 20566008Syy154373 cmn_err(CE_WARN, 20576008Syy154373 "arcmsr%d: timeout while waiting for 'abort all " 20586008Syy154373 "outstanding commands'", 20596008Syy154373 ddi_get_instance(acb->dev_info)); 20606008Syy154373 } 20616008Syy154373} 20626008Syy154373 20636008Syy154373static void 20646008Syy154373arcmsr_report_ccb_state(struct ACB *acb, 20656008Syy154373 struct CCB *ccb, uint32_t flag_ccb) { 20666008Syy154373 20676008Syy154373 int id, lun; 20686008Syy154373 20696008Syy154373 id = ccb->pkt->pkt_address.a_target; 20706008Syy154373 lun = ccb->pkt->pkt_address.a_lun; 20716008Syy154373 20726008Syy154373 if ((flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR) == 0) { 20736008Syy154373 if (acb->devstate[id][lun] == ARECA_RAID_GONE) { 20746008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GOOD; 20756008Syy154373 } 20766008Syy154373 ccb->pkt->pkt_reason = CMD_CMPLT; 20776008Syy154373 ccb->pkt->pkt_state |= STATE_XFERRED_DATA; 20786008Syy154373 arcmsr_ccb_complete(ccb, 1); 20796008Syy154373 } else { 20806008Syy154373 switch (ccb->arcmsr_cdb.DeviceStatus) { 20816008Syy154373 case ARCMSR_DEV_SELECT_TIMEOUT: 20826008Syy154373 if (acb->devstate[id][lun] == ARECA_RAID_GOOD) { 20836008Syy154373 cmn_err(CE_CONT, 20846008Syy154373 "arcmsr%d: raid volume was kicked out ", 20856008Syy154373 ddi_get_instance(acb->dev_info)); 20866008Syy154373 } 20876008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GONE; 20886008Syy154373 ccb->pkt->pkt_reason = CMD_TIMEOUT; 20896008Syy154373 ccb->pkt->pkt_statistics |= STAT_TIMEOUT; 20906008Syy154373 arcmsr_ccb_complete(ccb, 1); 20916008Syy154373 break; 20926008Syy154373 case ARCMSR_DEV_ABORTED: 20936008Syy154373 case ARCMSR_DEV_INIT_FAIL: 20946008Syy154373 cmn_err(CE_CONT, 20956008Syy154373 "arcmsr%d: isr got " 20966008Syy154373 "'ARCMSR_DEV_ABORTED' 'ARCMSR_DEV_INIT_FAIL'", 20976008Syy154373 ddi_get_instance(acb->dev_info)); 20986008Syy154373 cmn_err(CE_CONT, "arcmsr%d: raid volume was kicked " 20996008Syy154373 "out", ddi_get_instance(acb->dev_info)); 21006008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GONE; 21016008Syy154373 ccb->pkt->pkt_reason = CMD_DEV_GONE; 21026008Syy154373 ccb->pkt->pkt_statistics |= STAT_TERMINATED; 21036008Syy154373 arcmsr_ccb_complete(ccb, 1); 21046008Syy154373 break; 21056008Syy154373 case SCSISTAT_CHECK_CONDITION: 21066008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GOOD; 21076008Syy154373 arcmsr_report_sense_info(ccb); 21086008Syy154373 arcmsr_ccb_complete(ccb, 1); 21096008Syy154373 break; 21106008Syy154373 default: 21116008Syy154373 cmn_err(CE_WARN, "arcmsr%d: target %d lun %d " 21126008Syy154373 "isr received CMD_DONE with unknown " 21136008Syy154373 "DeviceStatus (0x%x)", 21146008Syy154373 ddi_get_instance(acb->dev_info), id, lun, 21156008Syy154373 ccb->arcmsr_cdb.DeviceStatus); 21166008Syy154373 cmn_err(CE_CONT, "arcmsr%d: raid volume was kicked " 21176008Syy154373 "out ", ddi_get_instance(acb->dev_info)); 21186008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GONE; 21196008Syy154373 /* unknown error or crc error just for retry */ 21206008Syy154373 ccb->pkt->pkt_reason = CMD_TRAN_ERR; 21216008Syy154373 ccb->pkt->pkt_statistics |= STAT_TERMINATED; 21226008Syy154373 arcmsr_ccb_complete(ccb, 1); 21236008Syy154373 break; 21246008Syy154373 } 21256008Syy154373 } 21266008Syy154373} 21276008Syy154373 21286008Syy154373 21296008Syy154373static void 21306008Syy154373arcmsr_drain_donequeue(struct ACB *acb, uint32_t flag_ccb) { 21316008Syy154373 21326008Syy154373 struct CCB *ccb; 21336008Syy154373 21346008Syy154373 /* check if command completed without error */ 21356008Syy154373 ccb = (struct CCB *)(acb->vir2phy_offset + 21366008Syy154373 (flag_ccb << 5)); /* frame must be aligned on 32 byte boundary */ 21376008Syy154373 21386008Syy154373 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { 21396008Syy154373 if (ccb->startdone == ARCMSR_CCB_ABORTED) { 21406008Syy154373 cmn_err(CE_CONT, 21416008Syy154373 "arcmsr%d: isr got aborted command " 21426008Syy154373 "while draining doneq", 21436008Syy154373 ddi_get_instance(acb->dev_info)); 21446008Syy154373 ccb->pkt->pkt_reason = CMD_ABORTED; 21456008Syy154373 ccb->pkt->pkt_statistics |= STAT_ABORTED; 21466008Syy154373 arcmsr_ccb_complete(ccb, 1); 21476008Syy154373 return; 21486008Syy154373 } 21496008Syy154373 21506008Syy154373 if (ccb->startdone == ARCMSR_CCB_RESET) { 21516008Syy154373 cmn_err(CE_CONT, 21526008Syy154373 "arcmsr%d: isr got command reset " 21536008Syy154373 "while draining doneq", 21546008Syy154373 ddi_get_instance(acb->dev_info)); 21556008Syy154373 ccb->pkt->pkt_reason = CMD_RESET; 21566008Syy154373 ccb->pkt->pkt_statistics |= STAT_BUS_RESET; 21576008Syy154373 arcmsr_ccb_complete(ccb, 1); 21586008Syy154373 return; 21596008Syy154373 } 21606008Syy154373 21616008Syy154373 cmn_err(CE_WARN, "arcmsr%d: isr got an illegal ccb command " 21626008Syy154373 "done while draining doneq", 21636008Syy154373 ddi_get_instance(acb->dev_info)); 21646008Syy154373 return; 21656008Syy154373 } 21666008Syy154373 arcmsr_report_ccb_state(acb, ccb, flag_ccb); 21676008Syy154373} 21686008Syy154373 21696008Syy154373 21706008Syy154373static void 21716008Syy154373arcmsr_done4abort_postqueue(struct ACB *acb) { 21726008Syy154373 21736008Syy154373 int i = 0; 21746008Syy154373 uint32_t flag_ccb; 21756008Syy154373 21766008Syy154373 switch (acb->adapter_type) { 21776008Syy154373 case ACB_ADAPTER_TYPE_A: 21786008Syy154373 { 21796008Syy154373 struct HBA_msgUnit *phbamu; 21806008Syy154373 uint32_t outbound_intstatus; 21816008Syy154373 21826008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 21836008Syy154373 /* clear and abort all outbound posted Q */ 21846008Syy154373 outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 21856008Syy154373 &phbamu->outbound_intstatus) & acb->outbound_int_enable; 21866008Syy154373 /* clear interrupt */ 21876008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 21886008Syy154373 &phbamu->outbound_intstatus, outbound_intstatus); 21896008Syy154373 while (((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 21906008Syy154373 &phbamu->outbound_queueport)) != 0xFFFFFFFF) && 21916008Syy154373 (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { 21926008Syy154373 arcmsr_drain_donequeue(acb, flag_ccb); 21936008Syy154373 } 21946008Syy154373 } 21956008Syy154373 break; 21966008Syy154373 21976008Syy154373 case ACB_ADAPTER_TYPE_B: 21986008Syy154373 { 21996008Syy154373 struct HBB_msgUnit *phbbmu; 22006008Syy154373 22016008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 22026008Syy154373 22036008Syy154373 /* clear all outbound posted Q */ 22046008Syy154373 /* clear doorbell interrupt */ 22056008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 22066008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 22076008Syy154373 ARCMSR_DOORBELL_INT_CLEAR_PATTERN); 22086008Syy154373 for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { 22096008Syy154373 if ((flag_ccb = phbbmu->done_qbuffer[i]) != 0) { 22106008Syy154373 phbbmu->done_qbuffer[i] = 0; 22116008Syy154373 arcmsr_drain_donequeue(acb, flag_ccb); 22126008Syy154373 } 22136008Syy154373 phbbmu->post_qbuffer[i] = 0; 22146008Syy154373 } /* drain reply FIFO */ 22156008Syy154373 phbbmu->doneq_index = 0; 22166008Syy154373 phbbmu->postq_index = 0; 22176008Syy154373 break; 22186008Syy154373 } 22196008Syy154373 } 22206008Syy154373} 22216008Syy154373 22226008Syy154373/* 22236008Syy154373 * Routine Description: Reset 80331 iop. 22246008Syy154373 * Arguments: 22256008Syy154373 * Return Value: Nothing. 22266008Syy154373 */ 22276008Syy154373static void 22286008Syy154373arcmsr_iop_reset(struct ACB *acb) { 22296008Syy154373 22306008Syy154373 struct CCB *ccb; 22316008Syy154373 uint32_t intmask_org; 22326008Syy154373 int i = 0; 22336008Syy154373 22346008Syy154373 if (acb->ccboutstandingcount > 0) { 22356008Syy154373 /* disable all outbound interrupt */ 22366008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 22376008Syy154373 /* talk to iop 331 outstanding command aborted */ 22386008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 22396008Syy154373 arcmsr_abort_hba_allcmd(acb); 22406008Syy154373 } else { 22416008Syy154373 arcmsr_abort_hbb_allcmd(acb); 22426008Syy154373 } 22436008Syy154373 /* clear and abort all outbound posted Q */ 22446008Syy154373 arcmsr_done4abort_postqueue(acb); 22456008Syy154373 22466008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 22476008Syy154373 ccb = acb->pccb_pool[i]; 22486008Syy154373 if (ccb->startdone == ARCMSR_CCB_START) { 22496008Syy154373 ccb->startdone = ARCMSR_CCB_RESET; 22506008Syy154373 ccb->pkt->pkt_reason = CMD_RESET; 22516008Syy154373 ccb->pkt->pkt_statistics |= STAT_BUS_RESET; 22526008Syy154373 arcmsr_ccb_complete(ccb, 1); 22536008Syy154373 } 22546008Syy154373 } 22556008Syy154373 /* enable all outbound interrupt */ 22566008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 22576008Syy154373 } 22586008Syy154373} 22596008Syy154373 22606008Syy154373/* 22616008Syy154373 * You can access the DMA address through the #defines: 22626008Syy154373 * dmac_address for 32-bit addresses and dmac_laddress for 64-bit addresses. 22636008Syy154373 * These macros are defined as follows: 22646008Syy154373 * 22656008Syy154373 * #define dmac_laddress _dmu._dmac_ll 22666008Syy154373 * #ifdef _LONG_LONG_HTOL 22676008Syy154373 * #define dmac_notused _dmu._dmac_la[0] 22686008Syy154373 * #define dmac_address _dmu._dmac_la[1] 22696008Syy154373 * #else 22706008Syy154373 * #define dmac_address _dmu._dmac_la[0] 22716008Syy154373 * #define dmac_notused _dmu._dmac_la[1] 22726008Syy154373 * #endif 22736008Syy154373 */ 22746008Syy154373/*ARGSUSED*/ 22756008Syy154373static void 22766008Syy154373arcmsr_build_ccb(struct CCB *ccb) { 22776008Syy154373 22786008Syy154373 struct scsi_pkt *pkt = ccb->pkt; 22796008Syy154373 struct ARCMSR_CDB *arcmsr_cdb; 22806008Syy154373 char *psge; 22816008Syy154373 uint32_t address_lo, address_hi; 22826008Syy154373 int arccdbsize = 0x30; 22836008Syy154373 uint8_t sgcount; 22846008Syy154373 22856008Syy154373 arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; 22866008Syy154373 psge = (char *)&arcmsr_cdb->sgu; 22876008Syy154373 22886008Syy154373 /* return the current time in seconds */ 22896008Syy154373 ccb->ccb_time = (time_t)(pkt->pkt_time + ddi_get_time()); 22906008Syy154373 bcopy((caddr_t)pkt->pkt_cdbp, arcmsr_cdb->Cdb, 22916008Syy154373 arcmsr_cdb->CdbLength); 22926008Syy154373 sgcount = ccb->arcmsr_cdb.sgcount; 22936008Syy154373 22946008Syy154373 if (sgcount) { 22956008Syy154373 int length, i; 22966008Syy154373 int cdb_sgcount = 0; 22976008Syy154373 int total_xfer_length = 0; 22986008Syy154373 22996008Syy154373 /* map stor port SG list to our iop SG List. */ 23006008Syy154373 for (i = 0; i < sgcount; i++) { 23016008Syy154373 /* Get physaddr of the current data pointer */ 23026008Syy154373 length = ccb->pkt_dmacookies[i].dmac_size; 23036008Syy154373 total_xfer_length += length; 23046008Syy154373 address_lo = dma_addr_lo32( 23056008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress); 23066008Syy154373 address_hi = dma_addr_hi32( 23076008Syy154373 ccb->pkt_dmacookies[i].dmac_laddress); 23086008Syy154373 23096008Syy154373 if (address_hi == 0) { 23106008Syy154373 struct SG32ENTRY *dma_sg; 23116008Syy154373 23126008Syy154373 dma_sg = (struct SG32ENTRY *)(intptr_t)psge; 23136008Syy154373 23146008Syy154373 dma_sg->address = address_lo; 23156008Syy154373 dma_sg->length = length; 23166008Syy154373 psge += sizeof (struct SG32ENTRY); 23176008Syy154373 arccdbsize += sizeof (struct SG32ENTRY); 23186008Syy154373 } else { 23196008Syy154373 int sg64s_size = 0; 23206008Syy154373 int tmplength = length; 23216008Syy154373 int64_t span4G, length0; 23226008Syy154373 struct SG64ENTRY *dma_sg; 23236008Syy154373 23246008Syy154373 /*LINTED*/ 23256008Syy154373 while (1) { 23266008Syy154373 dma_sg = 23276008Syy154373 (struct SG64ENTRY *)(intptr_t)psge; 23286008Syy154373 span4G = 23296008Syy154373 (int64_t)address_lo + tmplength; 23306008Syy154373 23316008Syy154373 dma_sg->addresshigh = address_hi; 23326008Syy154373 dma_sg->address = address_lo; 23336008Syy154373 if (span4G > 0x100000000ULL) { 23346008Syy154373 /* see if we cross 4G */ 23356008Syy154373 length0 = 0x100000000ULL - 23366008Syy154373 address_lo; 23376008Syy154373 dma_sg->length = 23386008Syy154373 (uint32_t)length0 | 23396008Syy154373 IS_SG64_ADDR; 23406008Syy154373 address_hi = address_hi + 1; 23416008Syy154373 address_lo = 0; 23426008Syy154373 tmplength = tmplength- 23436008Syy154373 (int32_t)length0; 23446008Syy154373 sg64s_size += 23456008Syy154373 sizeof (struct SG64ENTRY); 23466008Syy154373 psge += 23476008Syy154373 sizeof (struct SG64ENTRY); 23486008Syy154373 cdb_sgcount++; 23496008Syy154373 } else { 23506008Syy154373 dma_sg->length = tmplength | 23516008Syy154373 IS_SG64_ADDR; 23526008Syy154373 sg64s_size += 23536008Syy154373 sizeof (struct SG64ENTRY); 23546008Syy154373 psge += 23556008Syy154373 sizeof (struct SG64ENTRY); 23566008Syy154373 break; 23576008Syy154373 } 23586008Syy154373 } 23596008Syy154373 arccdbsize += sg64s_size; 23606008Syy154373 } 23616008Syy154373 cdb_sgcount++; 23626008Syy154373 } 23636008Syy154373 arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount; 23646008Syy154373 arcmsr_cdb->DataLength = total_xfer_length; 23656008Syy154373 if (arccdbsize > 256) { 23666008Syy154373 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; 23676008Syy154373 } 23686008Syy154373 } else { 23696008Syy154373 arcmsr_cdb->DataLength = 0; 23706008Syy154373 } 23716008Syy154373 23726008Syy154373 if (ccb->ccb_flags & CCB_FLAG_DMAWRITE) 23736008Syy154373 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; 23746008Syy154373} 23756008Syy154373 23766008Syy154373/* 23776008Syy154373 * arcmsr_post_ccb - Send a protocol specific ARC send postcard to a AIOC. 23786008Syy154373 * 23796008Syy154373 * handle: Handle of registered ARC protocol driver 23806008Syy154373 * adapter_id: AIOC unique identifier(integer) 23816008Syy154373 * pPOSTCARD_SEND: Pointer to ARC send postcard 23826008Syy154373 * 23836008Syy154373 * This routine posts a ARC send postcard to the request post FIFO of a 23846008Syy154373 * specific ARC adapter. 23856008Syy154373 */ 23866008Syy154373static int 23876008Syy154373arcmsr_post_ccb(struct ACB *acb, struct CCB *ccb) { 23886008Syy154373 23896008Syy154373 uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; 23906008Syy154373 struct scsi_pkt *pkt = ccb->pkt; 23916008Syy154373 struct ARCMSR_CDB *arcmsr_cdb; 23926008Syy154373 23936008Syy154373 arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; 23946008Syy154373 23956008Syy154373 /* Use correct offset and size for syncing */ 23966008Syy154373 if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size, 23976008Syy154373 DDI_DMA_SYNC_FORDEV) == DDI_FAILURE) 23986008Syy154373 return (DDI_FAILURE); 23996008Syy154373 24006008Syy154373 atomic_add_32((volatile uint32_t *)&acb->ccboutstandingcount, 1); 24016008Syy154373 ccb->startdone = ARCMSR_CCB_START; 24026008Syy154373 24036008Syy154373 switch (acb->adapter_type) { 24046008Syy154373 case ACB_ADAPTER_TYPE_A: 24056008Syy154373 { 24066008Syy154373 struct HBA_msgUnit *phbamu; 24076008Syy154373 24086008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 24096008Syy154373 24106008Syy154373 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { 24116008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 24126008Syy154373 &phbamu->inbound_queueport, 24136008Syy154373 cdb_shifted_phyaddr | 24146008Syy154373 ARCMSR_CCBPOST_FLAG_SGL_BSIZE); 24156008Syy154373 } else { 24166008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 24176008Syy154373 &phbamu->inbound_queueport, cdb_shifted_phyaddr); 24186008Syy154373 } 24196008Syy154373 if (pkt->pkt_flags & FLAG_NOINTR) 24206008Syy154373 arcmsr_polling_hba_ccbdone(acb, ccb); 24216008Syy154373 } 24226008Syy154373 break; 24236008Syy154373 case ACB_ADAPTER_TYPE_B: 24246008Syy154373 { 24256008Syy154373 struct HBB_msgUnit *phbbmu; 24266008Syy154373 int ending_index, index; 24276008Syy154373 24286008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 24296008Syy154373 mutex_enter(&acb->postq_mutex); 24306008Syy154373 index = phbbmu->postq_index; 24316008Syy154373 ending_index = ((index+1)%ARCMSR_MAX_HBB_POSTQUEUE); 24326008Syy154373 phbbmu->post_qbuffer[ending_index] = 0; 24336008Syy154373 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { 24346008Syy154373 phbbmu->post_qbuffer[index] = 24356008Syy154373 (cdb_shifted_phyaddr|ARCMSR_CCBPOST_FLAG_SGL_BSIZE); 24366008Syy154373 } else { 24376008Syy154373 phbbmu->post_qbuffer[index] = cdb_shifted_phyaddr; 24386008Syy154373 } 24396008Syy154373 index++; 24406008Syy154373 /* if last index number set it to 0 */ 24416008Syy154373 index %= ARCMSR_MAX_HBB_POSTQUEUE; 24426008Syy154373 phbbmu->postq_index = index; 24436008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 24446008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 24456008Syy154373 ARCMSR_DRV2IOP_CDB_POSTED); 24466008Syy154373 mutex_exit(&acb->postq_mutex); 24476008Syy154373 if (pkt->pkt_flags & FLAG_NOINTR) 24486008Syy154373 arcmsr_polling_hbb_ccbdone(acb, ccb); 24496008Syy154373 } 24506008Syy154373 break; 24516008Syy154373 } 24526008Syy154373 24536008Syy154373 return (DDI_SUCCESS); 24546008Syy154373} 24556008Syy154373 24566008Syy154373 24576008Syy154373 24586008Syy154373 24596008Syy154373static struct QBUFFER * 24606008Syy154373arcmsr_get_iop_rqbuffer(struct ACB *acb) { 24616008Syy154373 24626008Syy154373 struct QBUFFER *qb; 24636008Syy154373 24646008Syy154373 switch (acb->adapter_type) { 24656008Syy154373 case ACB_ADAPTER_TYPE_A: 24666008Syy154373 { 24676008Syy154373 struct HBA_msgUnit *phbamu; 24686008Syy154373 24696008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 24706008Syy154373 qb = (struct QBUFFER *)&phbamu->message_rbuffer; 24716008Syy154373 } 24726008Syy154373 break; 24736008Syy154373 case ACB_ADAPTER_TYPE_B: 24746008Syy154373 { 24756008Syy154373 struct HBB_msgUnit *phbbmu; 24766008Syy154373 24776008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 24786008Syy154373 qb = (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer; 24796008Syy154373 } 24806008Syy154373 break; 24816008Syy154373 } 24826008Syy154373 24836008Syy154373 return (qb); 24846008Syy154373} 24856008Syy154373 24866008Syy154373 24876008Syy154373 24886008Syy154373static struct QBUFFER * 24896008Syy154373arcmsr_get_iop_wqbuffer(struct ACB *acb) { 24906008Syy154373 24916008Syy154373 struct QBUFFER *qbuffer = NULL; 24926008Syy154373 24936008Syy154373 switch (acb->adapter_type) { 24946008Syy154373 case ACB_ADAPTER_TYPE_A: 24956008Syy154373 { 24966008Syy154373 struct HBA_msgUnit *phbamu; 24976008Syy154373 24986008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 24996008Syy154373 qbuffer = (struct QBUFFER *)&phbamu->message_wbuffer; 25006008Syy154373 } 25016008Syy154373 break; 25026008Syy154373 case ACB_ADAPTER_TYPE_B: 25036008Syy154373 { 25046008Syy154373 struct HBB_msgUnit *phbbmu; 25056008Syy154373 25066008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 25076008Syy154373 qbuffer = 25086008Syy154373 (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer; 25096008Syy154373 } 25106008Syy154373 break; 25116008Syy154373 } 25126008Syy154373 return (qbuffer); 25136008Syy154373} 25146008Syy154373 25156008Syy154373 25166008Syy154373 25176008Syy154373static void 25186008Syy154373arcmsr_iop_message_read(struct ACB *acb) { 25196008Syy154373 25206008Syy154373 switch (acb->adapter_type) { 25216008Syy154373 case ACB_ADAPTER_TYPE_A: 25226008Syy154373 { 25236008Syy154373 struct HBA_msgUnit *phbamu; 25246008Syy154373 25256008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 25266008Syy154373 /* let IOP know the data has been read */ 25276008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 25286008Syy154373 &phbamu->inbound_doorbell, 25296008Syy154373 ARCMSR_INBOUND_DRIVER_DATA_READ_OK); 25306008Syy154373 } 25316008Syy154373 break; 25326008Syy154373 case ACB_ADAPTER_TYPE_B: 25336008Syy154373 { 25346008Syy154373 struct HBB_msgUnit *phbbmu; 25356008Syy154373 25366008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 25376008Syy154373 /* let IOP know the data has been read */ 25386008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 25396008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 25406008Syy154373 ARCMSR_DRV2IOP_DATA_READ_OK); 25416008Syy154373 } 25426008Syy154373 break; 25436008Syy154373 } 25446008Syy154373} 25456008Syy154373 25466008Syy154373 25476008Syy154373 25486008Syy154373static void 25496008Syy154373arcmsr_iop_message_wrote(struct ACB *acb) { 25506008Syy154373 25516008Syy154373 switch (acb->adapter_type) { 25526008Syy154373 case ACB_ADAPTER_TYPE_A: 25536008Syy154373 { 25546008Syy154373 struct HBA_msgUnit *phbamu; 25556008Syy154373 25566008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 25576008Syy154373 /* 25586008Syy154373 * push inbound doorbell tell iop, driver data write ok 25596008Syy154373 * and wait reply on next hwinterrupt for next Qbuffer post 25606008Syy154373 */ 25616008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 25626008Syy154373 &phbamu->inbound_doorbell, 25636008Syy154373 ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK); 25646008Syy154373 } 25656008Syy154373 break; 25666008Syy154373 case ACB_ADAPTER_TYPE_B: 25676008Syy154373 { 25686008Syy154373 struct HBB_msgUnit *phbbmu; 25696008Syy154373 25706008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 25716008Syy154373 /* 25726008Syy154373 * push inbound doorbell tell iop, driver data was writen 25736008Syy154373 * successfully, then await reply on next hwinterrupt for 25746008Syy154373 * next Qbuffer post 25756008Syy154373 */ 25766008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 25776008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 25786008Syy154373 ARCMSR_DRV2IOP_DATA_WRITE_OK); 25796008Syy154373 } 25806008Syy154373 break; 25816008Syy154373 } 25826008Syy154373} 25836008Syy154373 25846008Syy154373 25856008Syy154373 25866008Syy154373static void 25876008Syy154373arcmsr_post_ioctldata2iop(struct ACB *acb) { 25886008Syy154373 25896008Syy154373 uint8_t *pQbuffer; 25906008Syy154373 struct QBUFFER *pwbuffer; 25916008Syy154373 uint8_t *iop_data; 25926008Syy154373 int32_t allxfer_len = 0; 25936008Syy154373 25946008Syy154373 pwbuffer = arcmsr_get_iop_wqbuffer(acb); 25956008Syy154373 iop_data = (uint8_t *)pwbuffer->data; 25966008Syy154373 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) { 25976008Syy154373 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); 25986008Syy154373 while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) && 25996008Syy154373 (allxfer_len < 124)) { 26006008Syy154373 pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx]; 26016008Syy154373 (void) memcpy(iop_data, pQbuffer, 1); 26026008Syy154373 acb->wqbuf_firstidx++; 26036008Syy154373 /* if last index number set it to 0 */ 26046008Syy154373 acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER; 26056008Syy154373 iop_data++; 26066008Syy154373 allxfer_len++; 26076008Syy154373 } 26086008Syy154373 pwbuffer->data_len = allxfer_len; 26096008Syy154373 /* 26106008Syy154373 * push inbound doorbell and wait reply at hwinterrupt 26116008Syy154373 * routine for next Qbuffer post 26126008Syy154373 */ 26136008Syy154373 arcmsr_iop_message_wrote(acb); 26146008Syy154373 } 26156008Syy154373} 26166008Syy154373 26176008Syy154373 26186008Syy154373 26196008Syy154373static void 26206008Syy154373arcmsr_stop_hba_bgrb(struct ACB *acb) { 26216008Syy154373 26226008Syy154373 struct HBA_msgUnit *phbamu; 26236008Syy154373 26246008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 26256008Syy154373 26266008Syy154373 acb->acb_flags &= ~ACB_F_MSG_START_BGRB; 26276008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 26286008Syy154373 &phbamu->inbound_msgaddr0, 26296008Syy154373 ARCMSR_INBOUND_MESG0_STOP_BGRB); 26306008Syy154373 if (!arcmsr_hba_wait_msgint_ready(acb)) 26316008Syy154373 cmn_err(CE_WARN, 26326008Syy154373 "arcmsr%d: timeout while waiting for background " 26336008Syy154373 "rebuild completion", 26346008Syy154373 ddi_get_instance(acb->dev_info)); 26356008Syy154373} 26366008Syy154373 26376008Syy154373 26386008Syy154373static void 26396008Syy154373arcmsr_stop_hbb_bgrb(struct ACB *acb) { 26406008Syy154373 26416008Syy154373 struct HBB_msgUnit *phbbmu; 26426008Syy154373 26436008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 26446008Syy154373 26456008Syy154373 acb->acb_flags &= ~ACB_F_MSG_START_BGRB; 26466008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 26476008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 26486008Syy154373 ARCMSR_MESSAGE_STOP_BGRB); 26496008Syy154373 26506008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) 26516008Syy154373 cmn_err(CE_WARN, 26526008Syy154373 "arcmsr%d: timeout while waiting for background " 26536008Syy154373 "rebuild completion", 26546008Syy154373 ddi_get_instance(acb->dev_info)); 26556008Syy154373} 26566008Syy154373 26576008Syy154373static int 26586008Syy154373arcmsr_iop_message_xfer(struct ACB *acb, struct scsi_pkt *pkt) { 26596008Syy154373 26606008Syy154373 struct CMD_MESSAGE_FIELD *pcmdmessagefld; 26616008Syy154373 struct CCB *ccb = pkt->pkt_ha_private; 26626008Syy154373 struct buf *bp = ccb->bp; 26636008Syy154373 uint8_t *pQbuffer; 26646008Syy154373 int retvalue = 0, transfer_len = 0; 26656008Syy154373 char *buffer; 26666008Syy154373 uint32_t controlcode; 26676008Syy154373 26686008Syy154373 26696008Syy154373 /* 4 bytes: Areca io control code */ 26706008Syy154373 controlcode = (uint32_t)pkt->pkt_cdbp[5] << 24 | 26716008Syy154373 (uint32_t)pkt->pkt_cdbp[6] << 16 | 26726008Syy154373 (uint32_t)pkt->pkt_cdbp[7] << 8 | 26736008Syy154373 (uint32_t)pkt->pkt_cdbp[8]; 26746008Syy154373 26756008Syy154373 if (bp->b_flags & (B_PHYS | B_PAGEIO)) 26766008Syy154373 bp_mapin(bp); 26776008Syy154373 26786008Syy154373 26796008Syy154373 buffer = bp->b_un.b_addr; 26806008Syy154373 transfer_len = bp->b_bcount; 26816008Syy154373 if (transfer_len > sizeof (struct CMD_MESSAGE_FIELD)) { 26826008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 26836008Syy154373 goto message_out; 26846008Syy154373 } 26856008Syy154373 26866008Syy154373 pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)(intptr_t)buffer; 26876008Syy154373 26886008Syy154373 switch (controlcode) { 26896008Syy154373 case ARCMSR_MESSAGE_READ_RQBUFFER: 26906008Syy154373 { 26916008Syy154373 unsigned long *ver_addr; 26926008Syy154373 uint8_t *ptmpQbuffer; 26936008Syy154373 int32_t allxfer_len = 0; 26946008Syy154373 26956008Syy154373 ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP); 26966008Syy154373 if (!ver_addr) { 26976008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 26986008Syy154373 goto message_out; 26996008Syy154373 } 27006008Syy154373 27016008Syy154373 ptmpQbuffer = (uint8_t *)ver_addr; 27026008Syy154373 while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) && 27036008Syy154373 (allxfer_len < (MSGDATABUFLEN - 1))) { 27046008Syy154373 pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx]; 27056008Syy154373 (void) memcpy(ptmpQbuffer, pQbuffer, 1); 27066008Syy154373 acb->rqbuf_firstidx++; 27076008Syy154373 acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER; 27086008Syy154373 ptmpQbuffer++; 27096008Syy154373 allxfer_len++; 27106008Syy154373 } 27116008Syy154373 27126008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 27136008Syy154373 struct QBUFFER *prbuffer; 27146008Syy154373 uint8_t *iop_data; 27156008Syy154373 int32_t iop_len; 27166008Syy154373 27176008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 27186008Syy154373 prbuffer = arcmsr_get_iop_rqbuffer(acb); 27196008Syy154373 iop_data = (uint8_t *)prbuffer->data; 27206008Syy154373 iop_len = (int32_t)prbuffer->data_len; 27216008Syy154373 27226008Syy154373 while (iop_len > 0) { 27236008Syy154373 pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx]; 27246008Syy154373 (void) memcpy(pQbuffer, iop_data, 1); 27256008Syy154373 acb->rqbuf_lastidx++; 27266008Syy154373 acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER; 27276008Syy154373 iop_data++; 27286008Syy154373 iop_len--; 27296008Syy154373 } 27306008Syy154373 arcmsr_iop_message_read(acb); 27316008Syy154373 } 27326008Syy154373 27336008Syy154373 (void) memcpy(pcmdmessagefld->messagedatabuffer, 27346008Syy154373 (uint8_t *)ver_addr, allxfer_len); 27356008Syy154373 pcmdmessagefld->cmdmessage.Length = allxfer_len; 27366008Syy154373 pcmdmessagefld->cmdmessage.ReturnCode = 27376008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 27386008Syy154373 kmem_free(ver_addr, MSGDATABUFLEN); 27396008Syy154373 } 27406008Syy154373 break; 27416008Syy154373 case ARCMSR_MESSAGE_WRITE_WQBUFFER: 27426008Syy154373 { 27436008Syy154373 unsigned long *ver_addr; 27446008Syy154373 int32_t my_empty_len, user_len, wqbuf_firstidx, wqbuf_lastidx; 27456008Syy154373 uint8_t *ptmpuserbuffer; 27466008Syy154373 27476008Syy154373 ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP); 27486008Syy154373 if (!ver_addr) { 27496008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 27506008Syy154373 goto message_out; 27516008Syy154373 } 27526008Syy154373 ptmpuserbuffer = (uint8_t *)ver_addr; 27536008Syy154373 user_len = pcmdmessagefld->cmdmessage.Length; 27546008Syy154373 (void) memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, 27556008Syy154373 user_len); 27566008Syy154373 wqbuf_lastidx = acb->wqbuf_lastidx; 27576008Syy154373 wqbuf_firstidx = acb->wqbuf_firstidx; 27586008Syy154373 if (wqbuf_lastidx != wqbuf_firstidx) { 27596008Syy154373 struct scsi_arq_status *arq_status; 27606008Syy154373 27616008Syy154373 arcmsr_post_ioctldata2iop(acb); 27626008Syy154373 arq_status = 27636008Syy154373 (struct scsi_arq_status *)(intptr_t) 27646008Syy154373 (pkt->pkt_scbp); 27656008Syy154373 bzero((caddr_t)arq_status, 27666008Syy154373 sizeof (struct scsi_arq_status)); 27676008Syy154373 arq_status->sts_rqpkt_reason = CMD_CMPLT; 27686008Syy154373 arq_status->sts_rqpkt_state = (STATE_GOT_BUS | 27696008Syy154373 STATE_GOT_TARGET |STATE_SENT_CMD | 27706008Syy154373 STATE_XFERRED_DATA | STATE_GOT_STATUS); 27716008Syy154373 27726008Syy154373 arq_status->sts_rqpkt_statistics = pkt->pkt_statistics; 27736008Syy154373 arq_status->sts_rqpkt_resid = 0; 27746008Syy154373 if (&arq_status->sts_sensedata != NULL) { 27756008Syy154373 struct scsi_extended_sense *sts_sensedata; 27766008Syy154373 27776008Syy154373 sts_sensedata = &arq_status->sts_sensedata; 27786008Syy154373 27796008Syy154373 /* has error report sensedata */ 27806008Syy154373 sts_sensedata->es_code = 0x0; 27816008Syy154373 sts_sensedata->es_valid = 0x01; 27826008Syy154373 sts_sensedata->es_key = KEY_ILLEGAL_REQUEST; 27836008Syy154373 /* AdditionalSenseLength */ 27846008Syy154373 sts_sensedata->es_add_len = 0x0A; 27856008Syy154373 /* AdditionalSenseCode */ 27866008Syy154373 sts_sensedata->es_add_code = 0x20; 27876008Syy154373 } 27886008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 27896008Syy154373 } else { 27906008Syy154373 my_empty_len = (wqbuf_firstidx-wqbuf_lastidx - 1) & 27916008Syy154373 (ARCMSR_MAX_QBUFFER - 1); 27926008Syy154373 if (my_empty_len >= user_len) { 27936008Syy154373 while (user_len > 0) { 27946008Syy154373 pQbuffer = 27956008Syy154373 &acb->wqbuffer[acb->wqbuf_lastidx]; 27966008Syy154373 (void) memcpy(pQbuffer, 27976008Syy154373 ptmpuserbuffer, 1); 27986008Syy154373 acb->wqbuf_lastidx++; 27996008Syy154373 acb->wqbuf_lastidx %= 28006008Syy154373 ARCMSR_MAX_QBUFFER; 28016008Syy154373 ptmpuserbuffer++; 28026008Syy154373 user_len--; 28036008Syy154373 } 28046008Syy154373 if (acb->acb_flags & 28056008Syy154373 ACB_F_MESSAGE_WQBUFFER_CLEARED) { 28066008Syy154373 acb->acb_flags &= 28076008Syy154373 ~ACB_F_MESSAGE_WQBUFFER_CLEARED; 28086008Syy154373 arcmsr_post_ioctldata2iop(acb); 28096008Syy154373 } 28106008Syy154373 } else { 28116008Syy154373 struct scsi_arq_status *arq_status; 28126008Syy154373 28136008Syy154373 /* has error report sensedata */ 28146008Syy154373 arq_status = 28156008Syy154373 (struct scsi_arq_status *) 28166008Syy154373 (intptr_t)(pkt->pkt_scbp); 28176008Syy154373 bzero((caddr_t)arq_status, 28186008Syy154373 sizeof (struct scsi_arq_status)); 28196008Syy154373 arq_status->sts_rqpkt_reason = CMD_CMPLT; 28206008Syy154373 arq_status->sts_rqpkt_state = (STATE_GOT_BUS | 28216008Syy154373 STATE_GOT_TARGET |STATE_SENT_CMD | 28226008Syy154373 STATE_XFERRED_DATA | STATE_GOT_STATUS); 28236008Syy154373 arq_status->sts_rqpkt_statistics = 28246008Syy154373 pkt->pkt_statistics; 28256008Syy154373 arq_status->sts_rqpkt_resid = 0; 28266008Syy154373 if (&arq_status->sts_sensedata != NULL) { 28276008Syy154373 struct scsi_extended_sense 28286008Syy154373 *sts_sensedata; 28296008Syy154373 28306008Syy154373 sts_sensedata = 28316008Syy154373 &arq_status->sts_sensedata; 28326008Syy154373 28336008Syy154373 /* has error report sensedata */ 28346008Syy154373 sts_sensedata->es_code = 0x0; 28356008Syy154373 sts_sensedata->es_valid = 0x01; 28366008Syy154373 sts_sensedata->es_key = 28376008Syy154373 KEY_ILLEGAL_REQUEST; 28386008Syy154373 /* AdditionalSenseLength */ 28396008Syy154373 sts_sensedata->es_add_len = 0x0A; 28406008Syy154373 /* AdditionalSenseCode */ 28416008Syy154373 sts_sensedata->es_add_code = 0x20; 28426008Syy154373 } 28436008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 28446008Syy154373 } 28456008Syy154373 } 28466008Syy154373 kmem_free(ver_addr, MSGDATABUFLEN); 28476008Syy154373 } 28486008Syy154373 break; 28496008Syy154373 case ARCMSR_MESSAGE_CLEAR_RQBUFFER: 28506008Syy154373 { 28516008Syy154373 pQbuffer = acb->rqbuffer; 28526008Syy154373 28536008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 28546008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 28556008Syy154373 arcmsr_iop_message_read(acb); 28566008Syy154373 } 28576008Syy154373 acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; 28586008Syy154373 acb->rqbuf_firstidx = 0; 28596008Syy154373 acb->rqbuf_lastidx = 0; 28606008Syy154373 (void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 28616008Syy154373 pcmdmessagefld->cmdmessage.ReturnCode = 28626008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 28636008Syy154373 } 28646008Syy154373 break; 28656008Syy154373 case ARCMSR_MESSAGE_CLEAR_WQBUFFER: 28666008Syy154373 { 28676008Syy154373 pQbuffer = acb->wqbuffer; 28686008Syy154373 28696008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 28706008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 28716008Syy154373 arcmsr_iop_message_read(acb); 28726008Syy154373 } 28736008Syy154373 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | 28746008Syy154373 ACB_F_MESSAGE_WQBUFFER_READ); 28756008Syy154373 acb->wqbuf_firstidx = 0; 28766008Syy154373 acb->wqbuf_lastidx = 0; 28776008Syy154373 (void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 28786008Syy154373 pcmdmessagefld->cmdmessage.ReturnCode = 28796008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 28806008Syy154373 } 28816008Syy154373 break; 28826008Syy154373 case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: 28836008Syy154373 { 28846008Syy154373 28856008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 28866008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 28876008Syy154373 arcmsr_iop_message_read(acb); 28886008Syy154373 } 28896008Syy154373 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | 28906008Syy154373 ACB_F_MESSAGE_RQBUFFER_CLEARED | 28916008Syy154373 ACB_F_MESSAGE_WQBUFFER_READ); 28926008Syy154373 acb->rqbuf_firstidx = 0; 28936008Syy154373 acb->rqbuf_lastidx = 0; 28946008Syy154373 acb->wqbuf_firstidx = 0; 28956008Syy154373 acb->wqbuf_lastidx = 0; 28966008Syy154373 pQbuffer = acb->rqbuffer; 28976008Syy154373 (void) memset(pQbuffer, 0, sizeof (struct QBUFFER)); 28986008Syy154373 pQbuffer = acb->wqbuffer; 28996008Syy154373 (void) memset(pQbuffer, 0, sizeof (struct QBUFFER)); 29006008Syy154373 pcmdmessagefld->cmdmessage.ReturnCode = 29016008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 29026008Syy154373 } 29036008Syy154373 break; 29046008Syy154373 case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F: 29056008Syy154373 pcmdmessagefld->cmdmessage.ReturnCode = 29066008Syy154373 ARCMSR_MESSAGE_RETURNCODE_3F; 29076008Syy154373 break; 29086008Syy154373 /* 29096008Syy154373 * Not supported - ARCMSR_MESSAGE_SAY_HELLO 29106008Syy154373 */ 29116008Syy154373 case ARCMSR_MESSAGE_SAY_GOODBYE: 29126008Syy154373 arcmsr_iop_parking(acb); 29136008Syy154373 break; 29146008Syy154373 case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: 29156008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 29166008Syy154373 arcmsr_flush_hba_cache(acb); 29176008Syy154373 } else { 29186008Syy154373 arcmsr_flush_hbb_cache(acb); 29196008Syy154373 } 29206008Syy154373 break; 29216008Syy154373 default: 29226008Syy154373 retvalue = ARCMSR_MESSAGE_FAIL; 29236008Syy154373 } 29246008Syy154373 29256008Syy154373message_out: 29266008Syy154373 29276008Syy154373 return (retvalue); 29286008Syy154373} 29296008Syy154373 29306008Syy154373 29316008Syy154373 29326008Syy154373static int 29336008Syy154373arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg, int mode, 29346008Syy154373 cred_t *credp, int *rvalp) { 29356008Syy154373#ifndef __lock_lint 29366008Syy154373 _NOTE(ARGUNUSED(rvalp)) 29376008Syy154373#endif 29386008Syy154373 29396008Syy154373 struct ACB *acb; 29406008Syy154373 struct CMD_MESSAGE_FIELD *pktioctlfld; 29416008Syy154373 int retvalue = 0; 29426008Syy154373 int instance = MINOR2INST(getminor(dev)); 29436008Syy154373 29446008Syy154373 if (instance < 0) 29456008Syy154373 return (ENXIO); 29466008Syy154373 29476008Syy154373 if (secpolicy_sys_config(credp, B_FALSE) != 0) 29486008Syy154373 return (EPERM); 29496008Syy154373 29506008Syy154373 acb = ddi_get_soft_state(arcmsr_soft_state, instance); 29516008Syy154373 if (acb == NULL) 29526008Syy154373 return (ENXIO); 29536008Syy154373 29546008Syy154373 pktioctlfld = kmem_zalloc(sizeof (struct CMD_MESSAGE_FIELD), 29556008Syy154373 KM_SLEEP); 29566008Syy154373 if (pktioctlfld == NULL) 29576008Syy154373 return (ENXIO); 29586008Syy154373 29596008Syy154373 /* 29606008Syy154373 * if we got here, we either are a 64-bit app in a 64-bit kernel 29616008Syy154373 * or a 32-bit app in a 32-bit kernel. Either way, we can just 29626008Syy154373 * copy in the args without any special conversions. 29636008Syy154373 */ 29646008Syy154373 29656008Syy154373 mutex_enter(&acb->ioctl_mutex); 29666008Syy154373 if (ddi_copyin((void *)arg, pktioctlfld, 29676008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) { 29686008Syy154373 retvalue = ENXIO; 29696008Syy154373 goto ioctl_out; 29706008Syy154373 } 29716008Syy154373 29726008Syy154373 if (memcmp(pktioctlfld->cmdmessage.Signature, "ARCMSR", 6) != 0) { 29736008Syy154373 /* validity check */ 29746008Syy154373 retvalue = ENXIO; 29756008Syy154373 goto ioctl_out; 29766008Syy154373 } 29776008Syy154373 29786008Syy154373 switch ((unsigned int)ioctl_cmd) { 29796008Syy154373 case ARCMSR_MESSAGE_READ_RQBUFFER: 29806008Syy154373 { 29816008Syy154373 unsigned long *ver_addr; 29826008Syy154373 uint8_t *pQbuffer, *ptmpQbuffer; 29836008Syy154373 int32_t allxfer_len = 0; 29846008Syy154373 29856008Syy154373 ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP); 29866008Syy154373 if (ver_addr == NULL) { 29876008Syy154373 retvalue = ENXIO; 29886008Syy154373 goto ioctl_out; 29896008Syy154373 } 29906008Syy154373 29916008Syy154373 ptmpQbuffer = (uint8_t *)ver_addr; 29926008Syy154373 while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) && 29936008Syy154373 (allxfer_len < (MSGDATABUFLEN - 1))) { 29946008Syy154373 /* copy READ QBUFFER to srb */ 29956008Syy154373 pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx]; 29966008Syy154373 (void) memcpy(ptmpQbuffer, pQbuffer, 1); 29976008Syy154373 acb->rqbuf_firstidx++; 29986008Syy154373 /* if last index number set it to 0 */ 29996008Syy154373 acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER; 30006008Syy154373 ptmpQbuffer++; 30016008Syy154373 allxfer_len++; 30026008Syy154373 } 30036008Syy154373 30046008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 30056008Syy154373 struct QBUFFER *prbuffer; 30066008Syy154373 uint8_t *pQbuffer; 30076008Syy154373 uint8_t *iop_data; 30086008Syy154373 int32_t iop_len; 30096008Syy154373 30106008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 30116008Syy154373 prbuffer = arcmsr_get_iop_rqbuffer(acb); 30126008Syy154373 iop_data = (uint8_t *)prbuffer->data; 30136008Syy154373 iop_len = (int32_t)prbuffer->data_len; 30146008Syy154373 /* 30156008Syy154373 * this iop data does no chance to make me overflow 30166008Syy154373 * again here, so just do it 30176008Syy154373 */ 30186008Syy154373 while (iop_len > 0) { 30196008Syy154373 pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx]; 30206008Syy154373 (void) memcpy(pQbuffer, iop_data, 1); 30216008Syy154373 acb->rqbuf_lastidx++; 30226008Syy154373 /* if last index number set it to 0 */ 30236008Syy154373 acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER; 30246008Syy154373 iop_data++; 30256008Syy154373 iop_len--; 30266008Syy154373 } 30276008Syy154373 /* let IOP know data has been read */ 30286008Syy154373 arcmsr_iop_message_read(acb); 30296008Syy154373 } 30306008Syy154373 (void) memcpy(pktioctlfld->messagedatabuffer, 30316008Syy154373 (uint8_t *)ver_addr, allxfer_len); 30326008Syy154373 pktioctlfld->cmdmessage.Length = allxfer_len; 30336008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 30346008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 30356008Syy154373 30366008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 30376008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 30386008Syy154373 retvalue = ENXIO; 30396008Syy154373 30406008Syy154373 kmem_free(ver_addr, MSGDATABUFLEN); 30416008Syy154373 } 30426008Syy154373 break; 30436008Syy154373 case ARCMSR_MESSAGE_WRITE_WQBUFFER: 30446008Syy154373 { 30456008Syy154373 unsigned long *ver_addr; 30466008Syy154373 int32_t my_empty_len, user_len; 30476008Syy154373 int32_t wqbuf_firstidx, wqbuf_lastidx; 30486008Syy154373 uint8_t *pQbuffer, *ptmpuserbuffer; 30496008Syy154373 30506008Syy154373 ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP); 30516008Syy154373 30526008Syy154373 if (ver_addr == NULL) { 30536008Syy154373 retvalue = ENXIO; 30546008Syy154373 goto ioctl_out; 30556008Syy154373 } 30566008Syy154373 30576008Syy154373 ptmpuserbuffer = (uint8_t *)ver_addr; 30586008Syy154373 user_len = pktioctlfld->cmdmessage.Length; 30596008Syy154373 (void) memcpy(ptmpuserbuffer, 30606008Syy154373 pktioctlfld->messagedatabuffer, user_len); 30616008Syy154373 /* 30626008Syy154373 * check ifdata xfer length of this request will overflow 30636008Syy154373 * my array qbuffer 30646008Syy154373 */ 30656008Syy154373 wqbuf_lastidx = acb->wqbuf_lastidx; 30666008Syy154373 wqbuf_firstidx = acb->wqbuf_firstidx; 30676008Syy154373 if (wqbuf_lastidx != wqbuf_firstidx) { 30686008Syy154373 arcmsr_post_ioctldata2iop(acb); 30696008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 30706008Syy154373 ARCMSR_MESSAGE_RETURNCODE_ERROR; 30716008Syy154373 } else { 30726008Syy154373 my_empty_len = (wqbuf_firstidx - wqbuf_lastidx - 1) 30736008Syy154373 & (ARCMSR_MAX_QBUFFER - 1); 30746008Syy154373 if (my_empty_len >= user_len) { 30756008Syy154373 while (user_len > 0) { 30766008Syy154373 /* copy srb data to wqbuffer */ 30776008Syy154373 pQbuffer = 30786008Syy154373 &acb->wqbuffer[acb->wqbuf_lastidx]; 30796008Syy154373 (void) memcpy(pQbuffer, 30806008Syy154373 ptmpuserbuffer, 1); 30816008Syy154373 acb->wqbuf_lastidx++; 30826008Syy154373 /* iflast index number set it to 0 */ 30836008Syy154373 acb->wqbuf_lastidx %= 30846008Syy154373 ARCMSR_MAX_QBUFFER; 30856008Syy154373 ptmpuserbuffer++; 30866008Syy154373 user_len--; 30876008Syy154373 } 30886008Syy154373 /* post first Qbuffer */ 30896008Syy154373 if (acb->acb_flags & 30906008Syy154373 ACB_F_MESSAGE_WQBUFFER_CLEARED) { 30916008Syy154373 acb->acb_flags &= 30926008Syy154373 ~ACB_F_MESSAGE_WQBUFFER_CLEARED; 30936008Syy154373 arcmsr_post_ioctldata2iop(acb); 30946008Syy154373 } 30956008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 30966008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 30976008Syy154373 } else { 30986008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 30996008Syy154373 ARCMSR_MESSAGE_RETURNCODE_ERROR; 31006008Syy154373 } 31016008Syy154373 } 31026008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 31036008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 31046008Syy154373 retvalue = ENXIO; 31056008Syy154373 31066008Syy154373 kmem_free(ver_addr, MSGDATABUFLEN); 31076008Syy154373 } 31086008Syy154373 break; 31096008Syy154373 case ARCMSR_MESSAGE_CLEAR_RQBUFFER: 31106008Syy154373 { 31116008Syy154373 uint8_t *pQbuffer = acb->rqbuffer; 31126008Syy154373 31136008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 31146008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 31156008Syy154373 arcmsr_iop_message_read(acb); 31166008Syy154373 } 31176008Syy154373 acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; 31186008Syy154373 acb->rqbuf_firstidx = 0; 31196008Syy154373 acb->rqbuf_lastidx = 0; 31206008Syy154373 bzero(pQbuffer, ARCMSR_MAX_QBUFFER); 31216008Syy154373 /* report success */ 31226008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 31236008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 31246008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 31256008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 31266008Syy154373 retvalue = ENXIO; 31276008Syy154373 31286008Syy154373 } 31296008Syy154373 break; 31306008Syy154373 case ARCMSR_MESSAGE_CLEAR_WQBUFFER: 31316008Syy154373 { 31326008Syy154373 uint8_t *pQbuffer = acb->wqbuffer; 31336008Syy154373 31346008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 31356008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 31366008Syy154373 arcmsr_iop_message_read(acb); 31376008Syy154373 } 31386008Syy154373 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | 31396008Syy154373 ACB_F_MESSAGE_WQBUFFER_READ); 31406008Syy154373 acb->wqbuf_firstidx = 0; 31416008Syy154373 acb->wqbuf_lastidx = 0; 31426008Syy154373 bzero(pQbuffer, ARCMSR_MAX_QBUFFER); 31436008Syy154373 /* report success */ 31446008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 31456008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 31466008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 31476008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 31486008Syy154373 retvalue = ENXIO; 31496008Syy154373 31506008Syy154373 } 31516008Syy154373 break; 31526008Syy154373 case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: 31536008Syy154373 { 31546008Syy154373 uint8_t *pQbuffer; 31556008Syy154373 31566008Syy154373 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 31576008Syy154373 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 31586008Syy154373 arcmsr_iop_message_read(acb); 31596008Syy154373 } 31606008Syy154373 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | 31616008Syy154373 ACB_F_MESSAGE_RQBUFFER_CLEARED | 31626008Syy154373 ACB_F_MESSAGE_WQBUFFER_READ); 31636008Syy154373 acb->rqbuf_firstidx = 0; 31646008Syy154373 acb->rqbuf_lastidx = 0; 31656008Syy154373 acb->wqbuf_firstidx = 0; 31666008Syy154373 acb->wqbuf_lastidx = 0; 31676008Syy154373 pQbuffer = acb->rqbuffer; 31686008Syy154373 bzero(pQbuffer, sizeof (struct QBUFFER)); 31696008Syy154373 pQbuffer = acb->wqbuffer; 31706008Syy154373 bzero(pQbuffer, sizeof (struct QBUFFER)); 31716008Syy154373 /* report success */ 31726008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 31736008Syy154373 ARCMSR_MESSAGE_RETURNCODE_OK; 31746008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 31756008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 31766008Syy154373 retvalue = ENXIO; 31776008Syy154373 31786008Syy154373 } 31796008Syy154373 break; 31806008Syy154373 case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F: 31816008Syy154373 { 31826008Syy154373 pktioctlfld->cmdmessage.ReturnCode = 31836008Syy154373 ARCMSR_MESSAGE_RETURNCODE_3F; 31846008Syy154373 if (ddi_copyout(pktioctlfld, (void *)arg, 31856008Syy154373 sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) 31866008Syy154373 retvalue = ENXIO; 31876008Syy154373 } 31886008Syy154373 break; 31896008Syy154373 /* Not supported: ARCMSR_MESSAGE_SAY_HELLO */ 31906008Syy154373 case ARCMSR_MESSAGE_SAY_GOODBYE: 31916008Syy154373 arcmsr_iop_parking(acb); 31926008Syy154373 break; 31936008Syy154373 case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: 31946008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 31956008Syy154373 arcmsr_flush_hba_cache(acb); 31966008Syy154373 } else { 31976008Syy154373 arcmsr_flush_hbb_cache(acb); 31986008Syy154373 } 31996008Syy154373 break; 32006008Syy154373 default: 32016008Syy154373 retvalue = ENOTTY; 32026008Syy154373 } 32036008Syy154373 32046008Syy154373ioctl_out: 32056008Syy154373 kmem_free(pktioctlfld, sizeof (struct CMD_MESSAGE_FIELD)); 32066008Syy154373 mutex_exit(&acb->ioctl_mutex); 32076008Syy154373 32086008Syy154373 return (retvalue); 32096008Syy154373} 32106008Syy154373 32116008Syy154373 32126008Syy154373 32136008Syy154373static struct CCB * 32146008Syy154373arcmsr_get_freeccb(struct ACB *acb) { 32156008Syy154373 32166008Syy154373 struct CCB *ccb; 32176008Syy154373 int workingccb_startindex, workingccb_doneindex; 32186008Syy154373 32196008Syy154373 32206008Syy154373 mutex_enter(&acb->workingQ_mutex); 32216008Syy154373 workingccb_doneindex = acb->workingccb_doneindex; 32226008Syy154373 workingccb_startindex = acb->workingccb_startindex; 32236008Syy154373 ccb = acb->ccbworkingQ[workingccb_startindex]; 32246008Syy154373 workingccb_startindex++; 32256008Syy154373 workingccb_startindex %= ARCMSR_MAX_FREECCB_NUM; 32266008Syy154373 if (workingccb_doneindex != workingccb_startindex) { 32276008Syy154373 acb->workingccb_startindex = workingccb_startindex; 32286008Syy154373 } else { 32296008Syy154373 ccb = NULL; 32306008Syy154373 } 32316008Syy154373 32326008Syy154373 mutex_exit(&acb->workingQ_mutex); 32336008Syy154373 return (ccb); 32346008Syy154373} 32356008Syy154373 32366008Syy154373 32376008Syy154373 32386008Syy154373static int 32396008Syy154373arcmsr_seek_cmd2abort(struct ACB *acb, 32406008Syy154373 struct scsi_pkt *abortpkt) { 32416008Syy154373 32426008Syy154373 struct CCB *ccb; 32436008Syy154373 uint32_t intmask_org = 0; 32446008Syy154373 int i = 0; 32456008Syy154373 32466008Syy154373 acb->num_aborts++; 32476008Syy154373 32486008Syy154373 if (abortpkt == NULL) { 32496008Syy154373 /* 32506008Syy154373 * if abortpkt is NULL, the upper layer needs us 32516008Syy154373 * to abort all commands 32526008Syy154373 */ 32536008Syy154373 if (acb->ccboutstandingcount != 0) { 32546008Syy154373 /* disable all outbound interrupt */ 32556008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 32566008Syy154373 /* clear and abort all outbound posted Q */ 32576008Syy154373 arcmsr_done4abort_postqueue(acb); 32586008Syy154373 /* talk to iop 331 outstanding command aborted */ 32596008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 32606008Syy154373 arcmsr_abort_hba_allcmd(acb); 32616008Syy154373 } else { 32626008Syy154373 arcmsr_abort_hbb_allcmd(acb); 32636008Syy154373 } 32646008Syy154373 32656008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 32666008Syy154373 ccb = acb->pccb_pool[i]; 32676008Syy154373 if (ccb->startdone == ARCMSR_CCB_START) { 32686008Syy154373 /* 32696008Syy154373 * this ccb will complete at 32706008Syy154373 * hwinterrupt 32716008Syy154373 */ 32726008Syy154373 ccb->startdone = ARCMSR_CCB_ABORTED; 32736008Syy154373 ccb->pkt->pkt_reason = CMD_ABORTED; 32746008Syy154373 ccb->pkt->pkt_statistics |= 32756008Syy154373 STAT_ABORTED; 32766008Syy154373 arcmsr_ccb_complete(ccb, 1); 32776008Syy154373 } 32786008Syy154373 } 32796008Syy154373 /* 32806008Syy154373 * enable outbound Post Queue, outbound 32816008Syy154373 * doorbell Interrupt 32826008Syy154373 */ 32836008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 32846008Syy154373 } 32856008Syy154373 return (DDI_SUCCESS); 32866008Syy154373 } 32876008Syy154373 32886008Syy154373 /* 32896008Syy154373 * It is the upper layer do abort command this lock 32906008Syy154373 * just prior to calling us. 32916008Syy154373 * First determine if we currently own this command. 32926008Syy154373 * Start by searching the device queue. If not found 32936008Syy154373 * at all, and the system wanted us to just abort the 32946008Syy154373 * command returnsuccess. 32956008Syy154373 */ 32966008Syy154373 32976008Syy154373 if (acb->ccboutstandingcount != 0) { 32986008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 32996008Syy154373 ccb = acb->pccb_pool[i]; 33006008Syy154373 if (ccb->startdone == ARCMSR_CCB_START) { 33016008Syy154373 if (ccb->pkt == abortpkt) { 33026008Syy154373 ccb->startdone = 33036008Syy154373 ARCMSR_CCB_ABORTED; 33046008Syy154373 goto abort_outstanding_cmd; 33056008Syy154373 } 33066008Syy154373 } 33076008Syy154373 } 33086008Syy154373 } 33096008Syy154373 33106008Syy154373 return (DDI_FAILURE); 33116008Syy154373 33126008Syy154373abort_outstanding_cmd: 33136008Syy154373 /* disable all outbound interrupts */ 33146008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 33156008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 33166008Syy154373 arcmsr_polling_hba_ccbdone(acb, ccb); 33176008Syy154373 } else { 33186008Syy154373 arcmsr_polling_hbb_ccbdone(acb, ccb); 33196008Syy154373 } 33206008Syy154373 33216008Syy154373 /* enable outbound Post Queue, outbound doorbell Interrupt */ 33226008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 33236008Syy154373 return (DDI_SUCCESS); 33246008Syy154373} 33256008Syy154373 33266008Syy154373 33276008Syy154373 33286008Syy154373static void 33296008Syy154373arcmsr_pcidev_disattach(struct ACB *acb) { 33306008Syy154373 33316008Syy154373 struct CCB *ccb; 33326008Syy154373 int i = 0; 33336008Syy154373 33346008Syy154373 /* disable all outbound interrupts */ 33356008Syy154373 (void) arcmsr_disable_allintr(acb); 33366008Syy154373 /* stop adapter background rebuild */ 33376008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 33386008Syy154373 arcmsr_stop_hba_bgrb(acb); 33396008Syy154373 arcmsr_flush_hba_cache(acb); 33406008Syy154373 } else { 33416008Syy154373 arcmsr_stop_hbb_bgrb(acb); 33426008Syy154373 arcmsr_flush_hbb_cache(acb); 33436008Syy154373 } 33446008Syy154373 /* abort all outstanding commands */ 33456008Syy154373 acb->acb_flags |= ACB_F_SCSISTOPADAPTER; 33466008Syy154373 acb->acb_flags &= ~ACB_F_IOP_INITED; 33476008Syy154373 33486008Syy154373 if (acb->ccboutstandingcount != 0) { 33496008Syy154373 /* clear and abort all outbound posted Q */ 33506008Syy154373 arcmsr_done4abort_postqueue(acb); 33516008Syy154373 /* talk to iop 331 outstanding command aborted */ 33526008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 33536008Syy154373 arcmsr_abort_hba_allcmd(acb); 33546008Syy154373 } else { 33556008Syy154373 arcmsr_abort_hbb_allcmd(acb); 33566008Syy154373 } 33576008Syy154373 33586008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 33596008Syy154373 ccb = acb->pccb_pool[i]; 33606008Syy154373 if (ccb->startdone == ARCMSR_CCB_START) { 33616008Syy154373 ccb->startdone = ARCMSR_CCB_ABORTED; 33626008Syy154373 ccb->pkt->pkt_reason = CMD_ABORTED; 33636008Syy154373 ccb->pkt->pkt_statistics |= STAT_ABORTED; 33646008Syy154373 arcmsr_ccb_complete(ccb, 1); 33656008Syy154373 } 33666008Syy154373 } 33676008Syy154373 } 33686008Syy154373} 33696008Syy154373 33706008Syy154373/* get firmware miscellaneous data */ 33716008Syy154373static void 33726008Syy154373arcmsr_get_hba_config(struct ACB *acb) { 33736008Syy154373 33746008Syy154373 struct HBA_msgUnit *phbamu; 33756008Syy154373 33766008Syy154373 char *acb_firm_model; 33776008Syy154373 char *acb_firm_version; 33786008Syy154373 char *acb_device_map; 33796008Syy154373 char *iop_firm_model; 33806008Syy154373 char *iop_firm_version; 33816008Syy154373 char *iop_device_map; 33826008Syy154373 int count; 33836008Syy154373 33846008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 33856008Syy154373 acb_firm_model = acb->firm_model; 33866008Syy154373 acb_firm_version = acb->firm_version; 33876008Syy154373 acb_device_map = acb->device_map; 33886008Syy154373 /* firm_model, 15 */ 33896008Syy154373 iop_firm_model = (char *) 33906008Syy154373 (&phbamu->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]); 33916008Syy154373 /* firm_version, 17 */ 33926008Syy154373 iop_firm_version = 33936008Syy154373 (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); 33946008Syy154373 33956008Syy154373 /* device_map, 21 */ 33966008Syy154373 iop_device_map = 33976008Syy154373 (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]); 33986008Syy154373 33996008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0, 34006008Syy154373 ARCMSR_INBOUND_MESG0_GET_CONFIG); 34016008Syy154373 34026008Syy154373 if (!arcmsr_hba_wait_msgint_ready(acb)) 34036008Syy154373 cmn_err(CE_CONT, 34046008Syy154373 "arcmsr%d: timeout while waiting for adapter firmware " 34056008Syy154373 "miscellaneous data", 34066008Syy154373 ddi_get_instance(acb->dev_info)); 34076008Syy154373 34086008Syy154373 count = 8; 34096008Syy154373 while (count) { 34106008Syy154373 *acb_firm_model = 34116008Syy154373 CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_model); 34126008Syy154373 acb_firm_model++; 34136008Syy154373 iop_firm_model++; 34146008Syy154373 count--; 34156008Syy154373 } 34166008Syy154373 34176008Syy154373 count = 16; 34186008Syy154373 while (count) { 34196008Syy154373 *acb_firm_version = 34206008Syy154373 CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_version); 34216008Syy154373 acb_firm_version++; 34226008Syy154373 iop_firm_version++; 34236008Syy154373 count--; 34246008Syy154373 } 34256008Syy154373 34266008Syy154373 count = 16; 34276008Syy154373 while (count) { 34286008Syy154373 *acb_device_map = 34296008Syy154373 CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_device_map); 34306008Syy154373 acb_device_map++; 34316008Syy154373 iop_device_map++; 34326008Syy154373 count--; 34336008Syy154373 } 34346008Syy154373 34356008Syy154373 cmn_err(CE_CONT, "arcmsr%d: ARECA RAID FIRMWARE VERSION %s", 34366008Syy154373 ddi_get_instance(acb->dev_info), acb->firm_version); 34376008Syy154373 34386008Syy154373 /* firm_request_len, 1 */ 34396008Syy154373 acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 34406008Syy154373 &phbamu->msgcode_rwbuffer[1]); 34416008Syy154373 /* firm_numbers_queue, 2 */ 34426008Syy154373 acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 34436008Syy154373 &phbamu->msgcode_rwbuffer[2]); 34446008Syy154373 /* firm_sdram_size, 3 */ 34456008Syy154373 acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 34466008Syy154373 &phbamu->msgcode_rwbuffer[3]); 34476008Syy154373 /* firm_ide_channels, 4 */ 34486008Syy154373 acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 34496008Syy154373 &phbamu->msgcode_rwbuffer[4]); 34506008Syy154373} 34516008Syy154373 34526008Syy154373/* get firmware miscellaneous data */ 34536008Syy154373static void 34546008Syy154373arcmsr_get_hbb_config(struct ACB *acb) { 34556008Syy154373 34566008Syy154373 struct HBB_msgUnit *phbbmu; 34576008Syy154373 char *acb_firm_model; 34586008Syy154373 char *acb_firm_version; 34596008Syy154373 char *acb_device_map; 34606008Syy154373 char *iop_firm_model; 34616008Syy154373 char *iop_firm_version; 34626008Syy154373 char *iop_device_map; 34636008Syy154373 int count; 34646008Syy154373 34656008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 34666008Syy154373 acb_firm_model = acb->firm_model; 34676008Syy154373 acb_firm_version = acb->firm_version; 34686008Syy154373 acb_device_map = acb->device_map; 34696008Syy154373 /* firm_model, 15 */ 34706008Syy154373 iop_firm_model = (char *) 34716008Syy154373 (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]); 34726008Syy154373 /* firm_version, 17 */ 34736008Syy154373 iop_firm_version = (char *) 34746008Syy154373 (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); 34756008Syy154373 /* device_map, 21 */ 34766008Syy154373 iop_device_map = (char *) 34776008Syy154373 (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]); 34786008Syy154373 34796008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 34806008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 34816008Syy154373 ARCMSR_MESSAGE_GET_CONFIG); 34826008Syy154373 34836008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) 34846008Syy154373 cmn_err(CE_CONT, 34856008Syy154373 "arcmsr%d: timeout while waiting for adapter firmware " 34866008Syy154373 "miscellaneous data", 34876008Syy154373 ddi_get_instance(acb->dev_info)); 34886008Syy154373 34896008Syy154373 count = 8; 34906008Syy154373 while (count) { 34916008Syy154373 *acb_firm_model = CHIP_REG_READ8(acb->reg_mu_acc_handle1, 34926008Syy154373 iop_firm_model); 34936008Syy154373 acb_firm_model++; 34946008Syy154373 iop_firm_model++; 34956008Syy154373 count--; 34966008Syy154373 } 34976008Syy154373 34986008Syy154373 count = 16; 34996008Syy154373 while (count) { 35006008Syy154373 *acb_firm_version = CHIP_REG_READ8(acb->reg_mu_acc_handle1, 35016008Syy154373 iop_firm_version); 35026008Syy154373 acb_firm_version++; 35036008Syy154373 iop_firm_version++; 35046008Syy154373 count--; 35056008Syy154373 } 35066008Syy154373 count = 16; 35076008Syy154373 while (count) { 35086008Syy154373 *acb_device_map = 35096008Syy154373 CHIP_REG_READ8(acb->reg_mu_acc_handle1, iop_device_map); 35106008Syy154373 acb_device_map++; 35116008Syy154373 iop_device_map++; 35126008Syy154373 count--; 35136008Syy154373 } 35146008Syy154373 35156008Syy154373 cmn_err(CE_CONT, "arcmsr%d: ARECA RAID FIRMWARE VERSION %s", 35166008Syy154373 ddi_get_instance(acb->dev_info), acb->firm_version); 35176008Syy154373 35186008Syy154373 /* firm_request_len, 1 */ 35196008Syy154373 acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle1, 35206008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1]); 35216008Syy154373 /* firm_numbers_queue, 2 */ 35226008Syy154373 acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle1, 35236008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2]); 35246008Syy154373 /* firm_sdram_size, 3 */ 35256008Syy154373 acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle1, 35266008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3]); 35276008Syy154373 /* firm_ide_channels, 4 */ 35286008Syy154373 acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle1, 35296008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4]); 35306008Syy154373} 35316008Syy154373 35326008Syy154373 35336008Syy154373 35346008Syy154373/* start background rebuild */ 35356008Syy154373static void 35366008Syy154373arcmsr_start_hba_bgrb(struct ACB *acb) { 35376008Syy154373 35386008Syy154373 struct HBA_msgUnit *phbamu; 35396008Syy154373 35406008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 35416008Syy154373 35426008Syy154373 acb->acb_flags |= ACB_F_MSG_START_BGRB; 35436008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 35446008Syy154373 &phbamu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB); 35456008Syy154373 35466008Syy154373 if (!arcmsr_hba_wait_msgint_ready(acb)) 35476008Syy154373 cmn_err(CE_WARN, 35486008Syy154373 "arcmsr%d: timeout while waiting for background " 35496008Syy154373 "rebuild to start", 35506008Syy154373 ddi_get_instance(acb->dev_info)); 35516008Syy154373} 35526008Syy154373 35536008Syy154373 35546008Syy154373static void 35556008Syy154373arcmsr_start_hbb_bgrb(struct ACB *acb) { 35566008Syy154373 35576008Syy154373 struct HBB_msgUnit *phbbmu; 35586008Syy154373 35596008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 35606008Syy154373 35616008Syy154373 acb->acb_flags |= ACB_F_MSG_START_BGRB; 35626008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 35636008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 35646008Syy154373 ARCMSR_MESSAGE_START_BGRB); 35656008Syy154373 35666008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) 35676008Syy154373 cmn_err(CE_WARN, 35686008Syy154373 "arcmsr%d: timeout while waiting for background " 35696008Syy154373 "rebuild to start", 35706008Syy154373 ddi_get_instance(acb->dev_info)); 35716008Syy154373} 35726008Syy154373 35736008Syy154373 35746008Syy154373static void 35756008Syy154373arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb) { 35766008Syy154373 35776008Syy154373 struct HBA_msgUnit *phbamu; 35786008Syy154373 struct CCB *ccb; 35796008Syy154373 uint32_t flag_ccb, outbound_intstatus; 35806008Syy154373 uint32_t poll_ccb_done = 0; 35816008Syy154373 uint32_t poll_count = 0; 35826008Syy154373 35836008Syy154373 35846008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 35856008Syy154373 35866008Syy154373polling_ccb_retry: 35876008Syy154373 poll_count++; 35886008Syy154373 outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 35896008Syy154373 &phbamu->outbound_intstatus) & acb->outbound_int_enable; 35906008Syy154373 35916008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus, 35926008Syy154373 outbound_intstatus); /* clear interrupt */ 35936008Syy154373 35946008Syy154373 /* Use correct offset and size for syncing */ 35956008Syy154373 if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size, 35966008Syy154373 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) 35976008Syy154373 return; 35986008Syy154373 35996008Syy154373 /*LINTED*/ 36006008Syy154373 while (1) { 36016008Syy154373 if ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 36026008Syy154373 &phbamu->outbound_queueport)) == 0xFFFFFFFF) { 36036008Syy154373 if (poll_ccb_done) { 36046008Syy154373 /* chip FIFO no ccb for completion already */ 36056008Syy154373 break; 36066008Syy154373 } else { 36076008Syy154373 drv_usecwait(25000); 36086008Syy154373 if ((poll_count > 100) && (poll_ccb != NULL)) { 36096008Syy154373 break; 36106008Syy154373 } 36116008Syy154373 if (acb->ccboutstandingcount == 0) { 36126008Syy154373 break; 36136008Syy154373 } 36146008Syy154373 goto polling_ccb_retry; 36156008Syy154373 } 36166008Syy154373 } 36176008Syy154373 36186008Syy154373 /* check ifcommand done with no error */ 36196008Syy154373 ccb = (struct CCB *)(acb->vir2phy_offset + 36206008Syy154373 (flag_ccb << 5)); /* frame must be 32 bytes aligned */ 36216008Syy154373 if (poll_ccb != NULL) 36226008Syy154373 poll_ccb_done = (ccb == poll_ccb) ? 1 : 0; 36236008Syy154373 36246008Syy154373 if ((ccb->acb != acb) || 36256008Syy154373 (ccb->startdone != ARCMSR_CCB_START)) { 36266008Syy154373 if (ccb->startdone == ARCMSR_CCB_ABORTED) { 36276008Syy154373 ccb->pkt->pkt_reason = CMD_ABORTED; 36286008Syy154373 ccb->pkt->pkt_statistics |= STAT_ABORTED; 36296008Syy154373 arcmsr_ccb_complete(ccb, 1); 36306008Syy154373 continue; 36316008Syy154373 } 36326008Syy154373 cmn_err(CE_WARN, "arcmsr%d: polling op got " 36336008Syy154373 "unexpected ccb command done", 36346008Syy154373 ddi_get_instance(acb->dev_info)); 36356008Syy154373 continue; 36366008Syy154373 } 36376008Syy154373 arcmsr_report_ccb_state(acb, ccb, flag_ccb); 36386008Syy154373 } /* drain reply FIFO */ 36396008Syy154373} 36406008Syy154373 36416008Syy154373 36426008Syy154373static void 36436008Syy154373arcmsr_polling_hbb_ccbdone(struct ACB *acb, 36446008Syy154373 struct CCB *poll_ccb) { 36456008Syy154373 36466008Syy154373 struct HBB_msgUnit *phbbmu; 36476008Syy154373 struct CCB *ccb; 36486008Syy154373 uint32_t flag_ccb; 36496008Syy154373 uint32_t poll_ccb_done = 0; 36506008Syy154373 uint32_t poll_count = 0; 36516008Syy154373 int index; 36526008Syy154373 36536008Syy154373 36546008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 36556008Syy154373 36566008Syy154373 36576008Syy154373polling_ccb_retry: 36586008Syy154373 poll_count++; 36596008Syy154373 /* clear doorbell interrupt */ 36606008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 36616008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 36626008Syy154373 ARCMSR_DOORBELL_INT_CLEAR_PATTERN); 36636008Syy154373 36646008Syy154373 /* Use correct offset and size for syncing */ 36656008Syy154373 if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size, 36666008Syy154373 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) 36676008Syy154373 return; 36686008Syy154373 36696008Syy154373 36706008Syy154373 /*LINTED*/ 36716008Syy154373 while (1) { 36726008Syy154373 index = phbbmu->doneq_index; 36736008Syy154373 if ((flag_ccb = phbbmu->done_qbuffer[index]) == 0) { 36746008Syy154373 if (poll_ccb_done) { 36756008Syy154373 /* chip FIFO no ccb for completion already */ 36766008Syy154373 break; 36776008Syy154373 } else { 36786008Syy154373 drv_usecwait(25000); 36796008Syy154373 if ((poll_count > 100) && (poll_ccb != NULL)) 36806008Syy154373 break; 36816008Syy154373 if (acb->ccboutstandingcount == 0) 36826008Syy154373 break; 36836008Syy154373 goto polling_ccb_retry; 36846008Syy154373 } 36856008Syy154373 } 36866008Syy154373 36876008Syy154373 phbbmu->done_qbuffer[index] = 0; 36886008Syy154373 index++; 36896008Syy154373 /* if last index number set it to 0 */ 36906008Syy154373 index %= ARCMSR_MAX_HBB_POSTQUEUE; 36916008Syy154373 phbbmu->doneq_index = index; 36926008Syy154373 /* check if command done with no error */ 36936008Syy154373 /* frame must be 32 bytes aligned */ 36946008Syy154373 ccb = (struct CCB *)(acb->vir2phy_offset + 36956008Syy154373 (flag_ccb << 5)); 36966008Syy154373 if (poll_ccb != NULL) 36976008Syy154373 poll_ccb_done = (ccb == poll_ccb) ? 1 : 0; 36986008Syy154373 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { 36996008Syy154373 if (ccb->startdone == ARCMSR_CCB_ABORTED) { 37006008Syy154373 ccb->pkt->pkt_reason = CMD_ABORTED; 37016008Syy154373 ccb->pkt->pkt_statistics |= STAT_ABORTED; 37026008Syy154373 arcmsr_ccb_complete(ccb, 1); 37036008Syy154373 continue; 37046008Syy154373 } 37056008Syy154373 cmn_err(CE_WARN, "arcmsr%d: polling op got" 37066008Syy154373 "unexpect ccb command done", 37076008Syy154373 ddi_get_instance(acb->dev_info)); 37086008Syy154373 continue; 37096008Syy154373 } 37106008Syy154373 arcmsr_report_ccb_state(acb, ccb, flag_ccb); 37116008Syy154373 } /* drain reply FIFO */ 37126008Syy154373} 37136008Syy154373 37146008Syy154373 37156008Syy154373/* 37166008Syy154373 * Function: arcmsr_tran_start(9E) 37176008Syy154373 * Description: Transport the command in pktp to the target device. 37186008Syy154373 * The command is not finished when this returns, only 37196008Syy154373 * sent to the target; arcmsr_interrupt will call 37206008Syy154373 * (*pktp->pkt_comp)(pktp) when the target device has done. 37216008Syy154373 * 37226008Syy154373 * Input: struct scsi_address *ap, struct scsi_pkt *pktp 37236008Syy154373 * Output: TRAN_ACCEPT if pkt is OK and not driver not busy 37246008Syy154373 * TRAN_BUSY if driver is 37256008Syy154373 * TRAN_BADPKT if pkt is invalid 37266008Syy154373 */ 37276008Syy154373static int 37286008Syy154373arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) { 37296008Syy154373 37306008Syy154373 struct ACB *acb; 37316008Syy154373 struct CCB *ccb; 37326008Syy154373 int target = ap->a_target; 37336008Syy154373 int lun = ap->a_lun; 37346008Syy154373 37356008Syy154373 37366008Syy154373 acb = (struct ACB *)ap->a_hba_tran->tran_hba_private; 37376008Syy154373 ccb = pkt->pkt_ha_private; 37386008Syy154373 37396008Syy154373 if ((ccb->ccb_flags & CCB_FLAG_DMAVALID) && 37406008Syy154373 (ccb->ccb_flags & DDI_DMA_CONSISTENT)) 37416008Syy154373 (void) ddi_dma_sync(ccb->pkt_dma_handle, ccb->pkt_dma_offset, 37426008Syy154373 ccb->pkt_dma_len, DDI_DMA_SYNC_FORDEV); 37436008Syy154373 37446008Syy154373 37456008Syy154373 if (ccb->startdone == ARCMSR_CCB_UNBUILD) 37466008Syy154373 arcmsr_build_ccb(ccb); 37476008Syy154373 37486008Syy154373 37496008Syy154373 if (acb->acb_flags & ACB_F_BUS_RESET) { 37506008Syy154373 cmn_err(CE_CONT, 37516008Syy154373 "arcmsr%d: bus reset returned busy", 37526008Syy154373 ddi_get_instance(acb->dev_info)); 37536008Syy154373 pkt->pkt_reason = CMD_RESET; 37546008Syy154373 pkt->pkt_statistics |= STAT_BUS_RESET; 37556008Syy154373 pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | 37566008Syy154373 STATE_SENT_CMD | STATE_GOT_STATUS); 37576008Syy154373 if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) && 37586008Syy154373 (pkt->pkt_state & STATE_XFERRED_DATA)) 37596008Syy154373 (void) ddi_dma_sync(ccb->pkt_dma_handle, 37606008Syy154373 ccb->pkt_dma_offset, ccb->pkt_dma_len, 37616008Syy154373 DDI_DMA_SYNC_FORCPU); 37626008Syy154373 37636008Syy154373 scsi_hba_pkt_comp(pkt); 37646008Syy154373 37656008Syy154373 return (TRAN_ACCEPT); 37666008Syy154373 } 37676008Syy154373 37686008Syy154373 if (acb->devstate[target][lun] == ARECA_RAID_GONE) { 37696008Syy154373 uint8_t block_cmd; 37706008Syy154373 37716008Syy154373 block_cmd = pkt->pkt_cdbp[0] & 0x0f; 37726008Syy154373 37736008Syy154373 if (block_cmd == 0x08 || block_cmd == 0x0a) { 37746008Syy154373 cmn_err(CE_CONT, 37756008Syy154373 "arcmsr%d: block read/write command while raid" 37766008Syy154373 "volume missing (cmd %02x for target %d lun %d)", 37776008Syy154373 ddi_get_instance(acb->dev_info), 37786008Syy154373 block_cmd, target, lun); 37796008Syy154373 pkt->pkt_reason = CMD_TIMEOUT; 37806008Syy154373 pkt->pkt_statistics |= CMD_TIMEOUT; 37816008Syy154373 pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | 37826008Syy154373 STATE_SENT_CMD | STATE_GOT_STATUS); 37836008Syy154373 37846008Syy154373 if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) && 37856008Syy154373 (pkt->pkt_state & STATE_XFERRED_DATA)) 37866008Syy154373 (void) ddi_dma_sync(ccb->pkt_dma_handle, 37876008Syy154373 ccb->pkt_dma_offset, ccb->pkt_dma_len, 37886008Syy154373 DDI_DMA_SYNC_FORCPU); 37896008Syy154373 37906008Syy154373 37916008Syy154373 if (pkt->pkt_comp) 37926008Syy154373 (*pkt->pkt_comp)(pkt); 37936008Syy154373 37946008Syy154373 37956008Syy154373 return (TRAN_ACCEPT); 37966008Syy154373 } 37976008Syy154373 } 37986008Syy154373 37996008Syy154373 38006008Syy154373 /* IMPORTANT: Target 16 is a virtual device for iop message transfer */ 38016008Syy154373 if (target == 16) { 38026008Syy154373 38036008Syy154373 struct buf *bp = ccb->bp; 38046008Syy154373 uint8_t scsicmd = pkt->pkt_cdbp[0]; 38056008Syy154373 38066008Syy154373 switch (scsicmd) { 38076008Syy154373 case SCMD_INQUIRY: { 38086008Syy154373 if (lun != 0) { 38096008Syy154373 ccb->pkt->pkt_reason = CMD_TIMEOUT; 38106008Syy154373 ccb->pkt->pkt_statistics |= STAT_TIMEOUT; 38116008Syy154373 arcmsr_ccb_complete(ccb, 0); 38126008Syy154373 return (TRAN_ACCEPT); 38136008Syy154373 } 38146008Syy154373 38156008Syy154373 if (bp && bp->b_un.b_addr && bp->b_bcount) { 38166008Syy154373 uint8_t inqdata[36]; 38176008Syy154373 38186008Syy154373 /* The EVDP and pagecode is not supported */ 38196008Syy154373 if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[2]) { 38206008Syy154373 inqdata[1] = 0xFF; 38216008Syy154373 inqdata[2] = 0x00; 38226008Syy154373 } else { 38236008Syy154373 /* Periph Qualifier & Periph Dev Type */ 38246008Syy154373 inqdata[0] = DTYPE_PROCESSOR; 38256008Syy154373 /* rem media bit & Dev Type Modifier */ 38266008Syy154373 inqdata[1] = 0; 38276008Syy154373 /* ISO, ECMA, & ANSI versions */ 38286008Syy154373 inqdata[2] = 0; 38296008Syy154373 /* length of additional data */ 38306008Syy154373 inqdata[4] = 31; 38316008Syy154373 /* Vendor Identification */ 38326008Syy154373 bcopy("Areca ", 38336008Syy154373 &inqdata[8], VIDLEN); 38346008Syy154373 /* Product Identification */ 38356008Syy154373 bcopy("RAID controller ", 38366008Syy154373 &inqdata[16], PIDLEN); 38376008Syy154373 /* Product Revision */ 38386008Syy154373 bcopy(&inqdata[32], 38396008Syy154373 "R001", REVLEN); 38406008Syy154373 if (bp->b_flags & (B_PHYS | B_PAGEIO)) 38416008Syy154373 bp_mapin(bp); 38426008Syy154373 38436008Syy154373 (void) memcpy(bp->b_un.b_addr, 38446008Syy154373 inqdata, sizeof (inqdata)); 38456008Syy154373 } 38466008Syy154373 ccb->pkt->pkt_state |= STATE_XFERRED_DATA; 38476008Syy154373 } 38486008Syy154373 arcmsr_ccb_complete(ccb, 0); 38496008Syy154373 return (TRAN_ACCEPT); 38506008Syy154373 } 38516008Syy154373 case SCMD_WRITE_BUFFER: 38526008Syy154373 case SCMD_READ_BUFFER: { 38536008Syy154373 if (arcmsr_iop_message_xfer(acb, pkt)) { 38546008Syy154373 /* error just for retry */ 38556008Syy154373 ccb->pkt->pkt_reason = CMD_TRAN_ERR; 38566008Syy154373 ccb->pkt->pkt_statistics |= STAT_TERMINATED; 38576008Syy154373 } 38586008Syy154373 ccb->pkt->pkt_state |= STATE_XFERRED_DATA; 38596008Syy154373 arcmsr_ccb_complete(ccb, 0); 38606008Syy154373 return (TRAN_ACCEPT); 38616008Syy154373 } 38626008Syy154373 default: 38636008Syy154373 ccb->pkt->pkt_state |= STATE_XFERRED_DATA; 38646008Syy154373 arcmsr_ccb_complete(ccb, 0); 38656008Syy154373 return (TRAN_ACCEPT); 38666008Syy154373 } 38676008Syy154373 } 38686008Syy154373 38696008Syy154373 if (acb->ccboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) { 38706008Syy154373 cmn_err(CE_CONT, 38716008Syy154373 "arcmsr%d: too many outstanding commands (%d > %d)", 38726008Syy154373 ddi_get_instance(acb->dev_info), 38736008Syy154373 acb->ccboutstandingcount, 38746008Syy154373 ARCMSR_MAX_OUTSTANDING_CMD); 38756008Syy154373 return (TRAN_BUSY); 38766008Syy154373 } else if (arcmsr_post_ccb(acb, ccb) == DDI_FAILURE) { 38776008Syy154373 cmn_err(CE_CONT, 38786008Syy154373 "arcmsr%d: post failure, ccboutstandingcount = %d", 38796008Syy154373 ddi_get_instance(acb->dev_info), 38806008Syy154373 acb->ccboutstandingcount); 38816008Syy154373 return (TRAN_BUSY); 38826008Syy154373 } 38836008Syy154373 38846008Syy154373 return (TRAN_ACCEPT); 38856008Syy154373} 38866008Syy154373 38876008Syy154373/* 38886008Syy154373 * Function: arcmsr_tran_abort(9E) 38896008Syy154373 * SCSA interface routine to abort pkt(s) in progress. 38906008Syy154373 * Aborts the pkt specified. If NULL pkt, aborts ALL pkts. 38916008Syy154373 * Output: Return 1 if success 38926008Syy154373 * Return 0 if failure 38936008Syy154373 */ 38946008Syy154373static int 38956008Syy154373arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *abortpkt) { 38966008Syy154373 38976008Syy154373 struct ACB *acb; 38986008Syy154373 int return_code; 38996008Syy154373 39006008Syy154373 acb = (struct ACB *)ap->a_hba_tran->tran_hba_private; 39016008Syy154373 39026008Syy154373 39036008Syy154373 cmn_err(CE_WARN, 39046008Syy154373 "arcmsr%d: tran_abort called for target %d lun %d", 39056008Syy154373 ddi_get_instance(acb->dev_info), ap->a_target, ap->a_lun); 39066008Syy154373 39076008Syy154373 while (acb->ccboutstandingcount != 0) { 39086008Syy154373 drv_usecwait(10000); 39096008Syy154373 } 39106008Syy154373 39116008Syy154373 mutex_enter(&acb->acb_mutex); 39126008Syy154373 return_code = arcmsr_seek_cmd2abort(acb, abortpkt); 39136008Syy154373 mutex_exit(&acb->acb_mutex); 39146008Syy154373 39156008Syy154373 if (return_code != DDI_SUCCESS) { 39166008Syy154373 cmn_err(CE_WARN, 39176008Syy154373 "arcmsr%d: abort command failed for target %d lun %d", 39186008Syy154373 ddi_get_instance(acb->dev_info), 39196008Syy154373 ap->a_target, ap->a_lun); 39206008Syy154373 return (0); 39216008Syy154373 } 39226008Syy154373 39236008Syy154373 return (1); 39246008Syy154373} 39256008Syy154373 39266008Syy154373 39276008Syy154373/* 39286008Syy154373 * Function: arcmsr_tran_reset(9E) 39296008Syy154373 * SCSA interface routine to perform scsi resets on either 39306008Syy154373 * a specified target or the bus (default). 39316008Syy154373 * Output: Return 1 if success 39326008Syy154373 * Return 0 if failure 39336008Syy154373 */ 39346008Syy154373static int 39356008Syy154373arcmsr_tran_reset(struct scsi_address *ap, int level) { 39366008Syy154373 39376008Syy154373 struct ACB *acb; 39386008Syy154373 int return_code = 1; 39396008Syy154373 int retry = 0; 39406008Syy154373 39416008Syy154373 39426008Syy154373 /* Are we in the middle of dumping core? */ 39436008Syy154373 if (ddi_in_panic()) 39446008Syy154373 return (return_code); 39456008Syy154373 39466008Syy154373 acb = (struct ACB *)ap->a_hba_tran->tran_hba_private; 39476008Syy154373 39486008Syy154373 cmn_err(CE_WARN, "arcmsr%d: tran reset (level 0x%x) called " 39496008Syy154373 "for target %d lun %d", 39506008Syy154373 ddi_get_instance(acb->dev_info), level, 39516008Syy154373 ap->a_target, ap->a_lun); 39526008Syy154373 mutex_enter(&acb->acb_mutex); 39536008Syy154373 39546008Syy154373 while ((acb->ccboutstandingcount > 0) && (retry < 400)) { 39556008Syy154373 (void) arcmsr_interrupt((caddr_t)acb); 39566008Syy154373 drv_usecwait(25000); 39576008Syy154373 retry++; 39586008Syy154373 } 39596008Syy154373 39606008Syy154373 switch (level) { 39616008Syy154373 case RESET_ALL: /* level 1 */ 39626008Syy154373 acb->num_resets++; 39636008Syy154373 acb->acb_flags |= ACB_F_BUS_RESET; 39646008Syy154373 if (acb->timeout_count) 39656008Syy154373 arcmsr_iop_reset(acb); 39666008Syy154373 acb->acb_flags &= ~ACB_F_BUS_RESET; 39676008Syy154373 return_code = 0; 39686008Syy154373 break; 39696008Syy154373 case RESET_TARGET: /* level 0 */ 39706008Syy154373 cmn_err(CE_WARN, "arcmsr%d: target reset not supported", 39716008Syy154373 ddi_get_instance(acb->dev_info)); 39726008Syy154373 return_code = 0; 39736008Syy154373 break; 39746008Syy154373 default: 39756008Syy154373 return_code = 0; 39766008Syy154373 } 39776008Syy154373 39786008Syy154373 mutex_exit(&acb->acb_mutex); 39796008Syy154373 return (return_code); 39806008Syy154373} 39816008Syy154373 39826008Syy154373 39836008Syy154373static void 39846008Syy154373arcmsr_log(struct ACB *acb, int level, char *fmt, ...) { 39856008Syy154373 39866008Syy154373 char buf[256]; 39876008Syy154373 va_list ap; 39886008Syy154373 39896008Syy154373 va_start(ap, fmt); 39906008Syy154373 (void) vsprintf(buf, fmt, ap); 39916008Syy154373 va_end(ap); 39926008Syy154373 scsi_log(acb ? acb->dev_info : NULL, "arcmsr", level, "%s", buf); 39936008Syy154373} 39946008Syy154373 39956008Syy154373 39966008Syy154373static void 39976008Syy154373arcmsr_iop2drv_data_wrote_handle(struct ACB *acb) { 39986008Syy154373 39996008Syy154373 struct QBUFFER *prbuffer; 40006008Syy154373 uint8_t *pQbuffer; 40016008Syy154373 uint8_t *iop_data; 40026008Syy154373 int my_empty_len, iop_len; 40036008Syy154373 int rqbuf_firstidx, rqbuf_lastidx; 40046008Syy154373 40056008Syy154373 /* check this iop data if overflow my rqbuffer */ 40066008Syy154373 rqbuf_lastidx = acb->rqbuf_lastidx; 40076008Syy154373 rqbuf_firstidx = acb->rqbuf_firstidx; 40086008Syy154373 prbuffer = arcmsr_get_iop_rqbuffer(acb); 40096008Syy154373 iop_data = (uint8_t *)prbuffer->data; 40106008Syy154373 iop_len = prbuffer->data_len; 40116008Syy154373 my_empty_len = (rqbuf_firstidx-rqbuf_lastidx - 1) & 40126008Syy154373 (ARCMSR_MAX_QBUFFER - 1); 40136008Syy154373 40146008Syy154373 if (my_empty_len >= iop_len) { 40156008Syy154373 while (iop_len > 0) { 40166008Syy154373 pQbuffer = &acb->rqbuffer[rqbuf_lastidx]; 40176008Syy154373 (void) memcpy(pQbuffer, iop_data, 1); 40186008Syy154373 rqbuf_lastidx++; 40196008Syy154373 /* if last index number set it to 0 */ 40206008Syy154373 rqbuf_lastidx %= ARCMSR_MAX_QBUFFER; 40216008Syy154373 iop_data++; 40226008Syy154373 iop_len--; 40236008Syy154373 } 40246008Syy154373 acb->rqbuf_lastidx = rqbuf_lastidx; 40256008Syy154373 arcmsr_iop_message_read(acb); 40266008Syy154373 /* signature, let IOP know data has been read */ 40276008Syy154373 } else { 40286008Syy154373 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; 40296008Syy154373 } 40306008Syy154373} 40316008Syy154373 40326008Syy154373 40336008Syy154373 40346008Syy154373static void 40356008Syy154373arcmsr_iop2drv_data_read_handle(struct ACB *acb) { 40366008Syy154373 40376008Syy154373 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ; 40386008Syy154373 /* 40396008Syy154373 * check if there are any mail packages from user space program 40406008Syy154373 * in my post bag, now is the time to send them into Areca's firmware 40416008Syy154373 */ 40426008Syy154373 40436008Syy154373 if (acb->wqbuf_firstidx != acb->wqbuf_lastidx) { 40446008Syy154373 40456008Syy154373 uint8_t *pQbuffer; 40466008Syy154373 struct QBUFFER *pwbuffer; 40476008Syy154373 uint8_t *iop_data; 40486008Syy154373 int allxfer_len = 0; 40496008Syy154373 40506008Syy154373 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); 40516008Syy154373 pwbuffer = arcmsr_get_iop_wqbuffer(acb); 40526008Syy154373 iop_data = (uint8_t *)pwbuffer->data; 40536008Syy154373 40546008Syy154373 while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) && 40556008Syy154373 (allxfer_len < 124)) { 40566008Syy154373 pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx]; 40576008Syy154373 (void) memcpy(iop_data, pQbuffer, 1); 40586008Syy154373 acb->wqbuf_firstidx++; 40596008Syy154373 /* if last index number set it to 0 */ 40606008Syy154373 acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER; 40616008Syy154373 iop_data++; 40626008Syy154373 allxfer_len++; 40636008Syy154373 } 40646008Syy154373 pwbuffer->data_len = allxfer_len; 40656008Syy154373 /* 40666008Syy154373 * push inbound doorbell, tell iop driver data write ok 40676008Syy154373 * await reply on next hwinterrupt for next Qbuffer post 40686008Syy154373 */ 40696008Syy154373 arcmsr_iop_message_wrote(acb); 40706008Syy154373 } 40716008Syy154373 40726008Syy154373 if (acb->wqbuf_firstidx == acb->wqbuf_lastidx) 40736008Syy154373 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; 40746008Syy154373} 40756008Syy154373 40766008Syy154373 40776008Syy154373static void 40786008Syy154373arcmsr_hba_doorbell_isr(struct ACB *acb) { 40796008Syy154373 40806008Syy154373 uint32_t outbound_doorbell; 40816008Syy154373 struct HBA_msgUnit *phbamu; 40826008Syy154373 40836008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 40846008Syy154373 40856008Syy154373 /* 40866008Syy154373 * Maybe here we need to check wrqbuffer_lock is locked or not 40876008Syy154373 * DOORBELL: ding! dong! 40886008Syy154373 * check if there are any mail need to pack from firmware 40896008Syy154373 */ 40906008Syy154373 40916008Syy154373 outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 40926008Syy154373 &phbamu->outbound_doorbell); 40936008Syy154373 /* clear doorbell interrupt */ 40946008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 40956008Syy154373 &phbamu->outbound_doorbell, outbound_doorbell); 40966008Syy154373 40976008Syy154373 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) 40986008Syy154373 arcmsr_iop2drv_data_wrote_handle(acb); 40996008Syy154373 41006008Syy154373 41016008Syy154373 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) 41026008Syy154373 arcmsr_iop2drv_data_read_handle(acb); 41036008Syy154373} 41046008Syy154373 41056008Syy154373 41066008Syy154373 41076008Syy154373static void 41086008Syy154373arcmsr_hba_postqueue_isr(struct ACB *acb) { 41096008Syy154373 41106008Syy154373 uint32_t flag_ccb; 41116008Syy154373 struct HBA_msgUnit *phbamu; 41126008Syy154373 41136008Syy154373 41146008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 41156008Syy154373 41166008Syy154373 /* areca cdb command done */ 41176008Syy154373 /* Use correct offset and size for syncing */ 41186008Syy154373 (void) ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size, 41196008Syy154373 DDI_DMA_SYNC_FORKERNEL); 41206008Syy154373 41216008Syy154373 while ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 41226008Syy154373 &phbamu->outbound_queueport)) != 0xFFFFFFFF) { 41236008Syy154373 /* check if command done with no error */ 41246008Syy154373 arcmsr_drain_donequeue(acb, flag_ccb); 41256008Syy154373 } /* drain reply FIFO */ 41266008Syy154373} 41276008Syy154373 41286008Syy154373static void arcmsr_dr_handle(struct ACB *acb) 41296008Syy154373{ 41306008Syy154373 char *acb_dev_map = (char *)acb->device_map; 41316008Syy154373 char *devicemap; 41326008Syy154373 int target, lun; 41336008Syy154373 char diff; 41346008Syy154373 int circ1; 41356008Syy154373 dev_info_t *dip; 41366008Syy154373 ddi_acc_handle_t reg; 41376008Syy154373 switch (acb->adapter_type) { 41386008Syy154373 case ACB_ADAPTER_TYPE_A: 41396008Syy154373 { 41406008Syy154373 struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *) 41416008Syy154373 acb->pmu; 41426008Syy154373 devicemap = (char *)&phbamu->msgcode_rwbuffer[21]; 41436008Syy154373 reg = acb->reg_mu_acc_handle0; 41446008Syy154373 } 41456008Syy154373 break; 41466008Syy154373 case ACB_ADAPTER_TYPE_B: 41476008Syy154373 { 41486008Syy154373 struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *) 41496008Syy154373 acb->pmu; 41506008Syy154373 devicemap = (char *) 41516008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[21]; 41526008Syy154373 reg = acb->reg_mu_acc_handle1; 41536008Syy154373 } 41546008Syy154373 break; 41556008Syy154373 } 41566008Syy154373 41576008Syy154373 for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) { 41586008Syy154373 diff = 41596008Syy154373 (*acb_dev_map)^CHIP_REG_READ8(reg, devicemap); 41606008Syy154373 if (diff != 0) { 41616008Syy154373 char temp; 41626008Syy154373 *acb_dev_map = 41636008Syy154373 CHIP_REG_READ8(reg, devicemap); 41646008Syy154373 temp = *acb_dev_map; 41656008Syy154373 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { 41666008Syy154373 if ((temp & 0x01) == 1 && (diff & 0x01) == 1) { 41676008Syy154373 ndi_devi_enter(acb->dev_info, &circ1); 41686008Syy154373 (void) arcmsr_config_lun(acb, target, 41696008Syy154373 lun, NULL); 41706008Syy154373 ndi_devi_exit(acb->dev_info, circ1); 41716008Syy154373 } else if ((temp & 0x01) == 0 && (diff & 0x01) 41726008Syy154373 == 1) { 41736008Syy154373 dip = arcmsr_find_child(acb, target, 41746008Syy154373 lun); 41756008Syy154373 if (dip != NULL) { 41766008Syy154373 (void) ndi_devi_offline(dip, 41776008Syy154373 NDI_DEVI_REMOVE); 41786008Syy154373 cmn_err(CE_NOTE, "arcmsr%d: " 41796008Syy154373 "T%dL%d offlined", 41806008Syy154373 ddi_get_instance 41816008Syy154373 (acb->dev_info), target, 41826008Syy154373 lun); 41836008Syy154373 } 41846008Syy154373 } 41856008Syy154373 temp >>= 1; 41866008Syy154373 diff >>= 1; 41876008Syy154373 } 41886008Syy154373 } 41896008Syy154373 devicemap++; 41906008Syy154373 acb_dev_map++; 41916008Syy154373 } 41926008Syy154373} 41936008Syy154373 41946008Syy154373static void arcmsr_hba_message_isr(struct ACB *acb) 41956008Syy154373{ 41966008Syy154373 struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *)acb->pmu; 41976008Syy154373 uint32_t *signature = (&phbamu->msgcode_rwbuffer[0]); 41986008Syy154373 uint32_t outbound_message; 41996008Syy154373 42006008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus, 42016008Syy154373 ARCMSR_MU_OUTBOUND_MESSAGE0_INT); 42026008Syy154373 42036008Syy154373 outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 42046008Syy154373 signature); 42056008Syy154373 if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) 42066008Syy154373 if ((ddi_taskq_dispatch(acb->taskq, (void (*)(void *)) 42076008Syy154373 arcmsr_dr_handle, acb, DDI_NOSLEEP)) != DDI_SUCCESS) 42086008Syy154373 cmn_err(CE_WARN, "DR task start failed"); 42096008Syy154373} 42106008Syy154373 42116008Syy154373static void arcmsr_hbb_message_isr(struct ACB *acb) 42126008Syy154373{ 42136008Syy154373 struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *)acb->pmu; 42146008Syy154373 uint32_t *signature = (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0]); 42156008Syy154373 uint32_t outbound_message; 42166008Syy154373 42176008Syy154373 /* clear interrupts */ 42186008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 42196008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 42206008Syy154373 ARCMSR_MESSAGE_INT_CLEAR_PATTERN); 42216008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 42226008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 42236008Syy154373 ARCMSR_DRV2IOP_END_OF_INTERRUPT); 42246008Syy154373 42256008Syy154373 outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 42266008Syy154373 signature); 42276008Syy154373 if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) 42286008Syy154373 if ((ddi_taskq_dispatch(acb->taskq, 42296008Syy154373 (void (*)(void *))arcmsr_dr_handle, acb, 42306008Syy154373 DDI_NOSLEEP)) != DDI_SUCCESS) { 42316008Syy154373 cmn_err(CE_WARN, "DR task start failed"); 42326008Syy154373 } 42336008Syy154373} 42346008Syy154373 42356008Syy154373static void 42366008Syy154373arcmsr_hbb_postqueue_isr(struct ACB *acb) { 42376008Syy154373 42386008Syy154373 int index; 42396008Syy154373 uint32_t flag_ccb; 42406008Syy154373 struct HBB_msgUnit *phbbmu; 42416008Syy154373 42426008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 42436008Syy154373 42446008Syy154373 42456008Syy154373 /* areca cdb command done */ 42466008Syy154373 index = phbbmu->doneq_index; 42476008Syy154373 42486008Syy154373 while ((flag_ccb = phbbmu->done_qbuffer[index]) != 0) { 42496008Syy154373 phbbmu->done_qbuffer[index] = 0; 42506008Syy154373 index++; 42516008Syy154373 /* if last index number set it to 0 */ 42526008Syy154373 index %= ARCMSR_MAX_HBB_POSTQUEUE; 42536008Syy154373 phbbmu->doneq_index = index; 42546008Syy154373 /* check if command done with no error */ 42556008Syy154373 arcmsr_drain_donequeue(acb, flag_ccb); 42566008Syy154373 } /* drain reply FIFO */ 42576008Syy154373} 42586008Syy154373 42596008Syy154373 42606008Syy154373 42616008Syy154373 42626008Syy154373 42636008Syy154373static uint_t 42646008Syy154373arcmsr_handle_hba_isr(struct ACB *acb) { 42656008Syy154373 42666008Syy154373 uint32_t outbound_intstatus; 42676008Syy154373 struct HBA_msgUnit *phbamu; 42686008Syy154373 42696008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 42706008Syy154373 42716008Syy154373 outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 42726008Syy154373 &phbamu->outbound_intstatus) & acb->outbound_int_enable; 42736008Syy154373 42746008Syy154373 if (!outbound_intstatus) 42756008Syy154373 /* it must be a shared irq */ 42766008Syy154373 return (DDI_INTR_UNCLAIMED); 42776008Syy154373 42786008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus, 42796008Syy154373 outbound_intstatus); /* clear interrupt */ 42806008Syy154373 42816008Syy154373 42826008Syy154373 /* MU doorbell interrupts */ 42836008Syy154373 42846008Syy154373 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) 42856008Syy154373 arcmsr_hba_doorbell_isr(acb); 42866008Syy154373 42876008Syy154373 /* MU post queue interrupts */ 42886008Syy154373 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) 42896008Syy154373 arcmsr_hba_postqueue_isr(acb); 42906008Syy154373 42916008Syy154373 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { 42926008Syy154373 arcmsr_hba_message_isr(acb); 42936008Syy154373 } 42946008Syy154373 42956008Syy154373 return (DDI_INTR_CLAIMED); 42966008Syy154373} 42976008Syy154373 42986008Syy154373 42996008Syy154373static uint_t 43006008Syy154373arcmsr_handle_hbb_isr(struct ACB *acb) { 43016008Syy154373 43026008Syy154373 uint32_t outbound_doorbell; 43036008Syy154373 struct HBB_msgUnit *phbbmu; 43046008Syy154373 43056008Syy154373 43066008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 43076008Syy154373 43086008Syy154373 outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 43096008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell) & acb->outbound_int_enable; 43106008Syy154373 43116008Syy154373 if (!outbound_doorbell) 43126008Syy154373 /* it must be a shared irq */ 43136008Syy154373 return (DDI_INTR_UNCLAIMED); 43146008Syy154373 43156008Syy154373 /* clear doorbell interrupt */ 43166008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 43176008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, ~outbound_doorbell); 43186008Syy154373 /* wait a cycle */ 43196008Syy154373 (void) CHIP_REG_READ32(acb->reg_mu_acc_handle0, 43206008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell); 43216008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 43226008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 43236008Syy154373 ARCMSR_DRV2IOP_END_OF_INTERRUPT); 43246008Syy154373 43256008Syy154373 /* MU ioctl transfer doorbell interrupts */ 43266008Syy154373 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) 43276008Syy154373 arcmsr_iop2drv_data_wrote_handle(acb); 43286008Syy154373 43296008Syy154373 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) 43306008Syy154373 arcmsr_iop2drv_data_read_handle(acb); 43316008Syy154373 43326008Syy154373 /* MU post queue interrupts */ 43336008Syy154373 if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) 43346008Syy154373 arcmsr_hbb_postqueue_isr(acb); 43356008Syy154373 43366008Syy154373 /* MU message interrupt */ 43376008Syy154373 43386008Syy154373 if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { 43396008Syy154373 arcmsr_hbb_message_isr(acb); 43406008Syy154373 } 43416008Syy154373 43426008Syy154373 return (DDI_INTR_CLAIMED); 43436008Syy154373} 43446008Syy154373 43456008Syy154373 43466008Syy154373static uint_t 43476008Syy154373arcmsr_interrupt(caddr_t arg) { 43486008Syy154373 43496008Syy154373 43506008Syy154373 struct ACB *acb = (struct ACB *)(intptr_t)arg; 43516008Syy154373 43526008Syy154373 switch (acb->adapter_type) { 43536008Syy154373 case ACB_ADAPTER_TYPE_A: 43546008Syy154373 return (arcmsr_handle_hba_isr(acb)); 43556008Syy154373 case ACB_ADAPTER_TYPE_B: 43566008Syy154373 return (arcmsr_handle_hbb_isr(acb)); 43576008Syy154373 default: 43586008Syy154373 cmn_err(CE_WARN, "arcmsr%d: unknown adapter type (%d)", 43596008Syy154373 ddi_get_instance(acb->dev_info), acb->adapter_type); 43606008Syy154373 return (DDI_INTR_UNCLAIMED); 43616008Syy154373 } 43626008Syy154373} 43636008Syy154373 43646008Syy154373 43656008Syy154373static void 43666008Syy154373arcmsr_wait_firmware_ready(struct ACB *acb) { 43676008Syy154373 43686008Syy154373 uint32_t firmware_state; 43696008Syy154373 43706008Syy154373 firmware_state = 0; 43716008Syy154373 43726008Syy154373 switch (acb->adapter_type) { 43736008Syy154373 case ACB_ADAPTER_TYPE_A: 43746008Syy154373 { 43756008Syy154373 struct HBA_msgUnit *phbamu; 43766008Syy154373 43776008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 43786008Syy154373 do { 43796008Syy154373 firmware_state = 43806008Syy154373 CHIP_REG_READ32(acb->reg_mu_acc_handle0, 43816008Syy154373 &phbamu->outbound_msgaddr1); 43826008Syy154373 } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) 43836008Syy154373 == 0); 43846008Syy154373 } 43856008Syy154373 break; 43866008Syy154373 case ACB_ADAPTER_TYPE_B: 43876008Syy154373 { 43886008Syy154373 struct HBB_msgUnit *phbbmu; 43896008Syy154373 43906008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 43916008Syy154373 do { 43926008Syy154373 firmware_state = 43936008Syy154373 CHIP_REG_READ32(acb->reg_mu_acc_handle0, 43946008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell); 43956008Syy154373 } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); 43966008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 43976008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 43986008Syy154373 ARCMSR_DRV2IOP_END_OF_INTERRUPT); 43996008Syy154373 } 44006008Syy154373 break; 44016008Syy154373 } 44026008Syy154373} 44036008Syy154373 44046008Syy154373static void 44056008Syy154373arcmsr_clear_doorbell_queue_buffer(struct ACB *acb) { 44066008Syy154373 44076008Syy154373 switch (acb->adapter_type) { 44086008Syy154373 case ACB_ADAPTER_TYPE_A: 44096008Syy154373 { 44106008Syy154373 struct HBA_msgUnit *phbamu; 44116008Syy154373 uint32_t outbound_doorbell; 44126008Syy154373 44136008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 44146008Syy154373 /* empty doorbell Qbuffer if door bell rung */ 44156008Syy154373 outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0, 44166008Syy154373 &phbamu->outbound_doorbell); 44176008Syy154373 /* clear doorbell interrupt */ 44186008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44196008Syy154373 &phbamu->outbound_doorbell, outbound_doorbell); 44206008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44216008Syy154373 &phbamu->inbound_doorbell, 44226008Syy154373 ARCMSR_INBOUND_DRIVER_DATA_READ_OK); 44236008Syy154373 } 44246008Syy154373 break; 44256008Syy154373 case ACB_ADAPTER_TYPE_B: 44266008Syy154373 { 44276008Syy154373 struct HBB_msgUnit *phbbmu; 44286008Syy154373 44296008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 44306008Syy154373 44316008Syy154373 /* clear interrupt and message state */ 44326008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44336008Syy154373 &phbbmu->hbb_doorbell->iop2drv_doorbell, 44346008Syy154373 ARCMSR_MESSAGE_INT_CLEAR_PATTERN); 44356008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44366008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 44376008Syy154373 ARCMSR_DRV2IOP_DATA_READ_OK); 44386008Syy154373 /* let IOP know data has been read */ 44396008Syy154373 } 44406008Syy154373 break; 44416008Syy154373 } 44426008Syy154373} 44436008Syy154373 44446008Syy154373 44456008Syy154373static uint32_t 44466008Syy154373arcmsr_iop_confirm(struct ACB *acb) { 44476008Syy154373 44486008Syy154373 unsigned long ccb_phyaddr; 44496008Syy154373 uint32_t ccb_phyaddr_hi32; 44506008Syy154373 44516008Syy154373 /* 44526008Syy154373 * here we need to tell iop 331 about our freeccb.HighPart 44536008Syy154373 * if freeccb.HighPart is non-zero 44546008Syy154373 */ 44556008Syy154373 ccb_phyaddr = (unsigned long)acb->ccb_cookie.dmac_address; 44566008Syy154373 ccb_phyaddr_hi32 = (uint32_t)((ccb_phyaddr >> 16) >> 16); 44576008Syy154373 44586008Syy154373 switch (acb->adapter_type) { 44596008Syy154373 case ACB_ADAPTER_TYPE_A: 44606008Syy154373 { 44616008Syy154373 if (ccb_phyaddr_hi32 != 0) { 44626008Syy154373 struct HBA_msgUnit *phbamu; 44636008Syy154373 44646008Syy154373 phbamu = (struct HBA_msgUnit *)acb->pmu; 44656008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44666008Syy154373 &phbamu->msgcode_rwbuffer[0], 44676008Syy154373 ARCMSR_SIGNATURE_SET_CONFIG); 44686008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44696008Syy154373 &phbamu->msgcode_rwbuffer[1], ccb_phyaddr_hi32); 44706008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44716008Syy154373 &phbamu->inbound_msgaddr0, 44726008Syy154373 ARCMSR_INBOUND_MESG0_SET_CONFIG); 44736008Syy154373 if (!arcmsr_hba_wait_msgint_ready(acb)) { 44746008Syy154373 cmn_err(CE_WARN, 44756008Syy154373 "arcmsr%d: timeout setting ccb high " 44766008Syy154373 "physical address", 44776008Syy154373 ddi_get_instance(acb->dev_info)); 44786008Syy154373 return (FALSE); 44796008Syy154373 } 44806008Syy154373 } 44816008Syy154373 } 44826008Syy154373 break; 44836008Syy154373 44846008Syy154373 /* if adapter is type B, set window of "post command queue" */ 44856008Syy154373 44866008Syy154373 case ACB_ADAPTER_TYPE_B: 44876008Syy154373 { 44886008Syy154373 uint32_t post_queue_phyaddr; 44896008Syy154373 struct HBB_msgUnit *phbbmu; 44906008Syy154373 44916008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 44926008Syy154373 phbbmu->postq_index = 0; 44936008Syy154373 phbbmu->doneq_index = 0; 44946008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 44956008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 44966008Syy154373 ARCMSR_MESSAGE_SET_POST_WINDOW); 44976008Syy154373 44986008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) { 44996008Syy154373 cmn_err(CE_WARN, 45006008Syy154373 "arcmsr%d: timeout setting post command " 45016008Syy154373 "queue window", 45026008Syy154373 ddi_get_instance(acb->dev_info)); 45036008Syy154373 return (FALSE); 45046008Syy154373 } 45056008Syy154373 45066008Syy154373 post_queue_phyaddr = ccb_phyaddr + 45076008Syy154373 ARCMSR_MAX_FREECCB_NUM * 45086008Syy154373 sizeof (struct CCB) 45096008Syy154373 + ARCOFFSET(struct HBB_msgUnit, post_qbuffer); 45106008Syy154373 /* driver "set config" signature */ 45116008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle1, 45126008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0], 45136008Syy154373 ARCMSR_SIGNATURE_SET_CONFIG); 45146008Syy154373 /* normal should be zero */ 45156008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle1, 45166008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1], 45176008Syy154373 ccb_phyaddr_hi32); 45186008Syy154373 /* postQ size (256+8)*4 */ 45196008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle1, 45206008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2], 45216008Syy154373 post_queue_phyaddr); 45226008Syy154373 /* doneQ size (256+8)*4 */ 45236008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle1, 45246008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3], 45256008Syy154373 post_queue_phyaddr+1056); 45266008Syy154373 /* ccb maxQ size must be --> [(256+8)*4] */ 45276008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle1, 45286008Syy154373 &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4], 1056); 45296008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 45306008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 45316008Syy154373 ARCMSR_MESSAGE_SET_CONFIG); 45326008Syy154373 45336008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) { 45346008Syy154373 cmn_err(CE_WARN, 45356008Syy154373 "arcmsr%d: timeout setting command queue window", 45366008Syy154373 ddi_get_instance(acb->dev_info)); 45376008Syy154373 return (FALSE); 45386008Syy154373 } 45396008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 45406008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 45416008Syy154373 ARCMSR_MESSAGE_START_DRIVER_MODE); 45426008Syy154373 45436008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) { 45446008Syy154373 cmn_err(CE_WARN, 45456008Syy154373 "arcmsr%d: timeout in 'start driver mode'", 45466008Syy154373 ddi_get_instance(acb->dev_info)); 45476008Syy154373 return (FALSE); 45486008Syy154373 } 45496008Syy154373 } 45506008Syy154373 break; 45516008Syy154373 } 45526008Syy154373 return (TRUE); 45536008Syy154373} 45546008Syy154373 45556008Syy154373 45566008Syy154373/* 45576008Syy154373 * ONLY used for Adapter type B 45586008Syy154373 */ 45596008Syy154373static void 45606008Syy154373arcmsr_enable_eoi_mode(struct ACB *acb) { 45616008Syy154373 45626008Syy154373 struct HBB_msgUnit *phbbmu; 45636008Syy154373 45646008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 45656008Syy154373 45666008Syy154373 CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, 45676008Syy154373 &phbbmu->hbb_doorbell->drv2iop_doorbell, 45686008Syy154373 ARCMSR_MESSAGE_ACTIVE_EOI_MODE); 45696008Syy154373 45706008Syy154373 if (!arcmsr_hbb_wait_msgint_ready(acb)) 45716008Syy154373 cmn_err(CE_WARN, 45726008Syy154373 "arcmsr%d (Adapter type B): " 45736008Syy154373 "'iop enable eoi mode' timeout ", 45746008Syy154373 ddi_get_instance(acb->dev_info)); 45756008Syy154373 45766008Syy154373} 45776008Syy154373 45786008Syy154373/* start background rebuild */ 45796008Syy154373static void 45806008Syy154373arcmsr_iop_init(struct ACB *acb) { 45816008Syy154373 45826008Syy154373 uint32_t intmask_org; 45836008Syy154373 45846008Syy154373 /* disable all outbound interrupt */ 45856008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 45866008Syy154373 arcmsr_wait_firmware_ready(acb); 45876008Syy154373 (void) arcmsr_iop_confirm(acb); 45886008Syy154373 45896008Syy154373 /* start background rebuild */ 45906008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_A) { 45916008Syy154373 arcmsr_get_hba_config(acb); 45926008Syy154373 arcmsr_start_hba_bgrb(acb); 45936008Syy154373 } else { 45946008Syy154373 arcmsr_get_hbb_config(acb); 45956008Syy154373 arcmsr_start_hbb_bgrb(acb); 45966008Syy154373 } 45976008Syy154373 45986008Syy154373 /* empty doorbell Qbuffer if door bell rang */ 45996008Syy154373 arcmsr_clear_doorbell_queue_buffer(acb); 46006008Syy154373 46016008Syy154373 if (acb->adapter_type == ACB_ADAPTER_TYPE_B) 46026008Syy154373 arcmsr_enable_eoi_mode(acb); 46036008Syy154373 46046008Syy154373 /* enable outbound Post Queue, outbound doorbell Interrupt */ 46056008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 46066008Syy154373 acb->acb_flags |= ACB_F_IOP_INITED; 46076008Syy154373} 46086008Syy154373 46096008Syy154373 46106008Syy154373static int 46116008Syy154373arcmsr_initialize(struct ACB *acb) { 46126008Syy154373 46136008Syy154373 struct CCB *pccb_tmp; 46146008Syy154373 size_t allocated_length; 46156008Syy154373 uint16_t wval; 46166008Syy154373 uint32_t wlval; 46176008Syy154373 uint_t intmask_org, count; 46186008Syy154373 caddr_t arcmsr_ccbs_area; 46196008Syy154373 unsigned long ccb_phyaddr; 46206008Syy154373 int32_t dma_sync_size; 46216008Syy154373 int i, id, lun; 46226008Syy154373 46236008Syy154373 acb->irq = pci_config_get8(acb->pci_acc_handle, 46246008Syy154373 ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_LINE_REG); 46256008Syy154373 wlval = pci_config_get32(acb->pci_acc_handle, 0); 46266008Syy154373 wval = (uint16_t)((wlval >> 16) & 0xffff); 46276008Syy154373 46286008Syy154373 if (wval == PCI_DEVICE_ID_ARECA_1201) { 46296008Syy154373 uint32_t *iop_mu_regs_map0; 46306008Syy154373 uint32_t *iop_mu_regs_map1; 46316008Syy154373 struct CCB *freeccb; 46326008Syy154373 struct HBB_msgUnit *phbbmu; 46336008Syy154373 46346008Syy154373 acb->adapter_type = ACB_ADAPTER_TYPE_B; /* marvell */ 46356008Syy154373 dma_sync_size = (ARCMSR_MAX_FREECCB_NUM* 46366008Syy154373 sizeof (struct CCB) + 0x20) + 46376008Syy154373 sizeof (struct HBB_msgUnit); 46386008Syy154373 46396008Syy154373 46406008Syy154373 /* Allocate memory for the ccb */ 46416008Syy154373 if ((i = ddi_dma_alloc_handle(acb->dev_info, 46426008Syy154373 &arcmsr_ccb_attr, DDI_DMA_SLEEP, NULL, 46436008Syy154373 &acb->ccbs_pool_handle)) != DDI_SUCCESS) { 46446008Syy154373 switch (i) { 46456008Syy154373 case DDI_DMA_BADATTR: 46466008Syy154373 cmn_err(CE_WARN, 46476008Syy154373 "arcmsr%d: ddi_dma_alloc_handle got " 46486008Syy154373 "DDI_DMA_BADATTR", 46496008Syy154373 ddi_get_instance(acb->dev_info)); 46506008Syy154373 return (DDI_FAILURE); 46516008Syy154373 46526008Syy154373 case DDI_DMA_NORESOURCES: 46536008Syy154373 cmn_err(CE_WARN, "arcmsr%d: " 46546008Syy154373 "ddi_dma_alloc_handle got " 46556008Syy154373 "DDI_DMA_NORESOURCES ", 46566008Syy154373 ddi_get_instance(acb->dev_info)); 46576008Syy154373 return (DDI_FAILURE); 46586008Syy154373 } 46596008Syy154373 cmn_err(CE_WARN, 46606008Syy154373 "arcmsr%d: ddi_dma_alloc_handle got DDI_FAILURE", 46616008Syy154373 ddi_get_instance(acb->dev_info)); 46626008Syy154373 return (DDI_FAILURE); 46636008Syy154373 } 46646008Syy154373 46656008Syy154373 if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size, 46666008Syy154373 &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 46676008Syy154373 DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area, 46686008Syy154373 &allocated_length, &acb->ccbs_acc_handle) 46696008Syy154373 != DDI_SUCCESS) { 46706008Syy154373 cmn_err(CE_CONT, 46716008Syy154373 "arcmsr%d: ddi_dma_mem_alloc failed ", 46726008Syy154373 ddi_get_instance(acb->dev_info)); 46736008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 46746008Syy154373 return (DDI_FAILURE); 46756008Syy154373 } 46766008Syy154373 46776008Syy154373 if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL, 46786008Syy154373 (caddr_t)arcmsr_ccbs_area, dma_sync_size, 46796008Syy154373 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 46806008Syy154373 NULL, &acb->ccb_cookie, &count) != DDI_DMA_MAPPED) { 46816008Syy154373 cmn_err(CE_WARN, 46826008Syy154373 "arcmsr%d: ddi_dma_addr_bind_handle failed", 46836008Syy154373 ddi_get_instance(acb->dev_info)); 46846008Syy154373 ddi_dma_mem_free(&acb->ccbs_acc_handle); 46856008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 46866008Syy154373 return (DDI_FAILURE); 46876008Syy154373 } 46886008Syy154373 bzero(arcmsr_ccbs_area, dma_sync_size); 46896008Syy154373 freeccb = (struct CCB *)(intptr_t)arcmsr_ccbs_area; 46906008Syy154373 acb->pmu = (struct msgUnit *) 46916008Syy154373 &freeccb[ARCMSR_MAX_FREECCB_NUM]; 46926008Syy154373 phbbmu = (struct HBB_msgUnit *)acb->pmu; 46936008Syy154373 46946008Syy154373 /* setup device register */ 46956008Syy154373 if (ddi_regs_map_setup(acb->dev_info, 1, 46966008Syy154373 (caddr_t *)&iop_mu_regs_map0, 0, 46976008Syy154373 sizeof (struct HBB_DOORBELL), &acb->dev_acc_attr, 46986008Syy154373 &acb->reg_mu_acc_handle0) != DDI_SUCCESS) { 46996008Syy154373 arcmsr_log(NULL, CE_WARN, 47006008Syy154373 "arcmsr%d: unable to map PCI device " 47016008Syy154373 "base0 address registers", 47026008Syy154373 ddi_get_instance(acb->dev_info)); 47036008Syy154373 return (DDI_FAILURE); 47046008Syy154373 } 47056008Syy154373 47066008Syy154373 /* ARCMSR_DRV2IOP_DOORBELL */ 47076008Syy154373 phbbmu->hbb_doorbell = 47086008Syy154373 (struct HBB_DOORBELL *)iop_mu_regs_map0; 47096008Syy154373 if (ddi_regs_map_setup(acb->dev_info, 2, 47106008Syy154373 (caddr_t *)&iop_mu_regs_map1, 0, 47116008Syy154373 sizeof (struct HBB_RWBUFFER), &acb->dev_acc_attr, 47126008Syy154373 &acb->reg_mu_acc_handle1) != DDI_SUCCESS) { 47136008Syy154373 arcmsr_log(NULL, CE_WARN, 47146008Syy154373 "arcmsr%d: unable to map PCI device " 47156008Syy154373 "base1 address registers", 47166008Syy154373 ddi_get_instance(acb->dev_info)); 47176008Syy154373 return (DDI_FAILURE); 47186008Syy154373 } 47196008Syy154373 47206008Syy154373 /* ARCMSR_MSGCODE_RWBUFFER */ 47216008Syy154373 phbbmu->hbb_rwbuffer = 47226008Syy154373 (struct HBB_RWBUFFER *)iop_mu_regs_map1; 47236008Syy154373 } else { 47246008Syy154373 uint32_t *iop_mu_regs_map0; 47256008Syy154373 47266008Syy154373 acb->adapter_type = ACB_ADAPTER_TYPE_A; /* intel */ 47276008Syy154373 dma_sync_size = ARCMSR_MAX_FREECCB_NUM* 47286008Syy154373 sizeof (struct CCB) + 0x20; 47296008Syy154373 if (ddi_regs_map_setup(acb->dev_info, 1, 47306008Syy154373 (caddr_t *)&iop_mu_regs_map0, 0, 47316008Syy154373 sizeof (struct HBA_msgUnit), &acb->dev_acc_attr, 47326008Syy154373 &acb->reg_mu_acc_handle0) != DDI_SUCCESS) { 47336008Syy154373 arcmsr_log(NULL, CE_WARN, 47346008Syy154373 "arcmsr%d: unable to map registers", 47356008Syy154373 ddi_get_instance(acb->dev_info)); 47366008Syy154373 return (DDI_FAILURE); 47376008Syy154373 } 47386008Syy154373 47396008Syy154373 if ((i = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_ccb_attr, 47406008Syy154373 DDI_DMA_SLEEP, NULL, &acb->ccbs_pool_handle)) != 47416008Syy154373 DDI_SUCCESS) { 47426008Syy154373 switch (i) { 47436008Syy154373 case DDI_DMA_BADATTR: 47446008Syy154373 cmn_err(CE_WARN, 47456008Syy154373 "arcmsr%d: ddi_dma_alloc_handle " 47466008Syy154373 "got DDI_DMA_BADATTR", 47476008Syy154373 ddi_get_instance(acb->dev_info)); 47486008Syy154373 return (DDI_FAILURE); 47496008Syy154373 case DDI_DMA_NORESOURCES: 47506008Syy154373 cmn_err(CE_WARN, "arcmsr%d: " 47516008Syy154373 "ddi_dma_alloc_handle got " 47526008Syy154373 "DDI_DMA_NORESOURCES", 47536008Syy154373 ddi_get_instance(acb->dev_info)); 47546008Syy154373 return (DDI_FAILURE); 47556008Syy154373 } 47566008Syy154373 cmn_err(CE_WARN, 47576008Syy154373 "arcmsr%d: ddi_dma_alloc_handle failed", 47586008Syy154373 ddi_get_instance(acb->dev_info)); 47596008Syy154373 return (DDI_FAILURE); 47606008Syy154373 } 47616008Syy154373 47626008Syy154373 if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size, 47636008Syy154373 &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 47646008Syy154373 DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area, 47656008Syy154373 &allocated_length, &acb->ccbs_acc_handle) 47666008Syy154373 != DDI_SUCCESS) { 47676008Syy154373 cmn_err(CE_WARN, "arcmsr%d: ddi_dma_mem_alloc failed", 47686008Syy154373 ddi_get_instance(acb->dev_info)); 47696008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 47706008Syy154373 return (DDI_FAILURE); 47716008Syy154373 } 47726008Syy154373 47736008Syy154373 if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL, 47746008Syy154373 (caddr_t)arcmsr_ccbs_area, dma_sync_size, DDI_DMA_RDWR | 47756008Syy154373 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &acb->ccb_cookie, 47766008Syy154373 &count) != DDI_DMA_MAPPED) { 47776008Syy154373 cmn_err(CE_WARN, "arcmsr%d: ddi_dma_addr_bind_handle " 47786008Syy154373 "failed", 47796008Syy154373 ddi_get_instance(acb->dev_info)); 47806008Syy154373 ddi_dma_mem_free(&acb->ccbs_acc_handle); 47816008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 47826008Syy154373 return (DDI_FAILURE); 47836008Syy154373 } 47846008Syy154373 bzero(arcmsr_ccbs_area, dma_sync_size); 47856008Syy154373 /* ioport base */ 47866008Syy154373 acb->pmu = (struct msgUnit *)(intptr_t)iop_mu_regs_map0; 47876008Syy154373 } 47886008Syy154373 47896008Syy154373 /* here we can not access pci configuration again */ 47906008Syy154373 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | 47916008Syy154373 ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READ); 47926008Syy154373 acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; 47936008Syy154373 /* physical address of acb->pccb_pool */ 47946008Syy154373 ccb_phyaddr = acb->ccb_cookie.dmac_address; 47956008Syy154373 47966008Syy154373 if (((unsigned long)arcmsr_ccbs_area & 0x1F) != 0) { 47976008Syy154373 /* ccb address must 32 (0x20) boundary */ 47986008Syy154373 arcmsr_ccbs_area = (caddr_t)((unsigned long)arcmsr_ccbs_area + 47996008Syy154373 (0x20 - ((unsigned long)arcmsr_ccbs_area & 0x1F))); 48006008Syy154373 ccb_phyaddr = (unsigned long)ccb_phyaddr + 48016008Syy154373 (0x20 - ((unsigned long)ccb_phyaddr & 0x1F)); 48026008Syy154373 } 48036008Syy154373 48046008Syy154373 pccb_tmp = (struct CCB *)(intptr_t)arcmsr_ccbs_area; 48056008Syy154373 48066008Syy154373 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { 48076008Syy154373 pccb_tmp->cdb_shifted_phyaddr = ccb_phyaddr >> 5; 48086008Syy154373 pccb_tmp->acb = acb; 48096008Syy154373 acb->ccbworkingQ[i] = acb->pccb_pool[i] = pccb_tmp; 48106008Syy154373 ccb_phyaddr = ccb_phyaddr + sizeof (struct CCB); 48116008Syy154373 pccb_tmp++; 48126008Syy154373 } 48136008Syy154373 48146008Syy154373 acb->vir2phy_offset = (unsigned long)pccb_tmp - 48156008Syy154373 (unsigned long)ccb_phyaddr; 48166008Syy154373 48176008Syy154373 /* disable all outbound interrupt */ 48186008Syy154373 intmask_org = arcmsr_disable_allintr(acb); 48196008Syy154373 48206008Syy154373 if (!arcmsr_iop_confirm(acb)) { 48216008Syy154373 cmn_err(CE_WARN, "arcmsr%d: arcmsr_iop_confirm error", 48226008Syy154373 ddi_get_instance(acb->dev_info)); 48236008Syy154373 ddi_dma_mem_free(&acb->ccbs_acc_handle); 48246008Syy154373 ddi_dma_free_handle(&acb->ccbs_pool_handle); 48256008Syy154373 return (DDI_FAILURE); 48266008Syy154373 } 48276008Syy154373 48286008Syy154373 for (id = 0; id < ARCMSR_MAX_TARGETID; id++) { 48296008Syy154373 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { 48306008Syy154373 acb->devstate[id][lun] = ARECA_RAID_GONE; 48316008Syy154373 } 48326008Syy154373 } 48336008Syy154373 48346008Syy154373 /* enable outbound Post Queue, outbound doorbell Interrupt */ 48356008Syy154373 arcmsr_enable_allintr(acb, intmask_org); 48366008Syy154373 48376008Syy154373 return (0); 48386008Syy154373} 48396008Syy154373 48406008Syy154373/* 48416008Syy154373 * Autoconfiguration support 48426008Syy154373 */ 48436008Syy154373static int 48446008Syy154373arcmsr_parse_devname(char *devnm, int *tgt, int *lun) 48456008Syy154373{ 48466008Syy154373 char devbuf[SCSI_MAXNAMELEN]; 48476008Syy154373 char *addr; 48486008Syy154373 char *p, *tp, *lp; 48496008Syy154373 long num; 48506008Syy154373 48516008Syy154373 /* Parse dev name and address */ 48526008Syy154373 (void) strcpy(devbuf, devnm); 48536008Syy154373 addr = ""; 48546008Syy154373 for (p = devbuf; *p != '\0'; p++) { 48556008Syy154373 if (*p == '@') { 48566008Syy154373 addr = p + 1; 48576008Syy154373 *p = '\0'; 48586008Syy154373 } else if (*p == ':') { 48596008Syy154373 *p = '\0'; 48606008Syy154373 break; 48616008Syy154373 } 48626008Syy154373 } 48636008Syy154373 48646008Syy154373 /* Parse target and lun */ 48656008Syy154373 for (p = tp = addr, lp = NULL; *p != '\0'; p++) { 48666008Syy154373 if (*p == ',') { 48676008Syy154373 lp = p + 1; 48686008Syy154373 *p = '\0'; 48696008Syy154373 break; 48706008Syy154373 } 48716008Syy154373 } 48726008Syy154373 if (tgt && tp) { 48736008Syy154373 if (ddi_strtol(tp, NULL, 0x10, &num)) 48746008Syy154373 return (-1); 48756008Syy154373 *tgt = (int)num; 48766008Syy154373 } 48776008Syy154373 if (lun && lp) { 48786008Syy154373 if (ddi_strtol(lp, NULL, 0x10, &num)) 48796008Syy154373 return (-1); 48806008Syy154373 *lun = (int)num; 48816008Syy154373 } 48826008Syy154373 return (0); 48836008Syy154373} 48846008Syy154373 48856008Syy154373static int 48866008Syy154373arcmsr_name_node(dev_info_t *dip, char *name, int len) 48876008Syy154373{ 48886008Syy154373 int tgt, lun; 48896008Syy154373 48906008Syy154373 tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 48916008Syy154373 DDI_PROP_DONTPASS, "target", -1); 48926008Syy154373 if (tgt == -1) 48936008Syy154373 return (DDI_FAILURE); 48946008Syy154373 lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 48956008Syy154373 DDI_PROP_DONTPASS, "lun", -1); 48966008Syy154373 if (lun == -1) 48976008Syy154373 return (DDI_FAILURE); 48986008Syy154373 48996008Syy154373 (void) snprintf(name, len, "%x,%x", tgt, lun); 49006008Syy154373 return (DDI_SUCCESS); 49016008Syy154373} 49026008Syy154373 49036008Syy154373static dev_info_t * 49046008Syy154373arcmsr_find_child(struct ACB *acb, uint16_t tgt, uint8_t lun) 49056008Syy154373{ 49066008Syy154373 dev_info_t *child = NULL; 49076008Syy154373 char addr[SCSI_MAXNAMELEN]; 49086008Syy154373 char tmp[MAXNAMELEN]; 49096008Syy154373 49106008Syy154373 (void) sprintf(addr, "%x,%x", tgt, lun); 49116008Syy154373 for (child = ddi_get_child(acb->dev_info); 49126008Syy154373 child; child = ddi_get_next_sibling(child)) { 49136008Syy154373 /* We don't care about non-persistent node */ 49146008Syy154373 if (ndi_dev_is_persistent_node(child) == 0) 49156008Syy154373 continue; 49166008Syy154373 49176008Syy154373 if (arcmsr_name_node(child, tmp, MAXNAMELEN) != 49186008Syy154373 DDI_SUCCESS) 49196008Syy154373 continue; 49206008Syy154373 if (strcmp(addr, tmp) == 0) 49216008Syy154373 break; 49226008Syy154373 } 49236008Syy154373 return (child); 49246008Syy154373} 49256008Syy154373 49266008Syy154373static int 49276008Syy154373arcmsr_config_child(struct ACB *acb, struct scsi_device *sd, 49286008Syy154373 dev_info_t **dipp) 49296008Syy154373{ 49306008Syy154373 char *nodename = NULL; 49316008Syy154373 char **compatible = NULL; 49326008Syy154373 int ncompatible = 0; 49336008Syy154373 dev_info_t *ldip = NULL; 49346008Syy154373 int tgt = sd->sd_address.a_target; 49356008Syy154373 int lun = sd->sd_address.a_lun; 49366008Syy154373 int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK; 49376008Syy154373 int rval; 49386008Syy154373 49396008Syy154373 scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype, 49406008Syy154373 NULL, &nodename, &compatible, &ncompatible); 49416008Syy154373 if (nodename == NULL) { 49426008Syy154373 cmn_err(CE_WARN, 49436008Syy154373 "found no comptible driver for T%dL%d", tgt, lun); 49446008Syy154373 rval = NDI_FAILURE; 49456008Syy154373 goto finish; 49466008Syy154373 } 49476008Syy154373 49486008Syy154373 /* Create dev node */ 49496008Syy154373 rval = ndi_devi_alloc(acb->dev_info, nodename, DEVI_SID_NODEID, 49506008Syy154373 &ldip); 49516008Syy154373 if (rval == NDI_SUCCESS) { 49526008Syy154373 if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt) 49536008Syy154373 != DDI_PROP_SUCCESS) { 49546008Syy154373 cmn_err(CE_WARN, "arcmsr%d: unable to create " 49556008Syy154373 "property for T%dL%d (target)", 49566008Syy154373 ddi_get_instance(acb->dev_info), tgt, lun); 49576008Syy154373 rval = NDI_FAILURE; 49586008Syy154373 goto finish; 49596008Syy154373 } 49606008Syy154373 if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun) 49616008Syy154373 != DDI_PROP_SUCCESS) { 49626008Syy154373 cmn_err(CE_WARN, "arcmsr%d: unable to create " 49636008Syy154373 "property for T%dL%d (lun)", 49646008Syy154373 ddi_get_instance(acb->dev_info), tgt, lun); 49656008Syy154373 rval = NDI_FAILURE; 49666008Syy154373 goto finish; 49676008Syy154373 } 49686008Syy154373 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip, 49696008Syy154373 "compatible", compatible, ncompatible) 49706008Syy154373 != DDI_PROP_SUCCESS) { 49716008Syy154373 cmn_err(CE_WARN, "arcmsr%d: unable to create" 49726008Syy154373 "property for T%dL%d (compatible)", 49736008Syy154373 ddi_get_instance(acb->dev_info), tgt, lun); 49746008Syy154373 rval = NDI_FAILURE; 49756008Syy154373 goto finish; 49766008Syy154373 } 49776008Syy154373 49786008Syy154373 rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH); 49796008Syy154373 if (rval != NDI_SUCCESS) { 49806008Syy154373 cmn_err(CE_WARN, "arcmsr%d: unable to online T%dL%d", 49816008Syy154373 ddi_get_instance(acb->dev_info), tgt, lun); 49826008Syy154373 ndi_prop_remove_all(ldip); 49836008Syy154373 (void) ndi_devi_free(ldip); 49846008Syy154373 } else 49856008Syy154373 cmn_err(CE_NOTE, "arcmsr%d: T%dL%d onlined", 49866008Syy154373 ddi_get_instance(acb->dev_info), tgt, lun); 49876008Syy154373 } 49886008Syy154373finish: 49896008Syy154373 if (dipp) 49906008Syy154373 *dipp = ldip; 49916008Syy154373 49926008Syy154373 scsi_hba_nodename_compatible_free(nodename, compatible); 49936008Syy154373 return (rval); 49946008Syy154373} 49956008Syy154373 49966008Syy154373static int 49976008Syy154373arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun, 49986008Syy154373 dev_info_t **ldip) 49996008Syy154373{ 50006008Syy154373 struct scsi_device sd; 50016008Syy154373 dev_info_t *child; 50026008Syy154373 int rval; 50036008Syy154373 50046008Syy154373 if ((child = arcmsr_find_child(acb, tgt, lun)) != NULL) { 50056008Syy154373 if (ldip) 50066008Syy154373 *ldip = child; 50076008Syy154373 return (NDI_SUCCESS); 50086008Syy154373 } 50096008Syy154373 50106008Syy154373 bzero(&sd, sizeof (struct scsi_device)); 50116008Syy154373 sd.sd_address.a_hba_tran = acb->scsi_hba_transport; 50126008Syy154373 sd.sd_address.a_target = (uint16_t)tgt; 50136008Syy154373 sd.sd_address.a_lun = (uint8_t)lun; 50146008Syy154373 rval = scsi_hba_probe(&sd, NULL); 50156008Syy154373 if (rval == SCSIPROBE_EXISTS) 50166008Syy154373 rval = arcmsr_config_child(acb, &sd, ldip); 50176008Syy154373 scsi_unprobe(&sd); 50186008Syy154373 return (rval); 50196008Syy154373} 50206008Syy154373 50216008Syy154373static int 50226008Syy154373arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op, 50236008Syy154373 void *arg, dev_info_t **childp) 50246008Syy154373{ 50256008Syy154373 struct ACB *acb; 50266008Syy154373 int circ = 0; 50276008Syy154373 int rval; 50286008Syy154373 int tgt, lun; 50296008Syy154373 if ((acb = ddi_get_soft_state(arcmsr_soft_state, 50306008Syy154373 ddi_get_instance(parent))) == NULL) 50316008Syy154373 return (NDI_FAILURE); 50326008Syy154373 50336008Syy154373 ndi_devi_enter(parent, &circ); 50346008Syy154373 switch (op) { 50356008Syy154373 case BUS_CONFIG_ONE: 50366008Syy154373 if (arcmsr_parse_devname(arg, &tgt, &lun) != 0) { 50376008Syy154373 rval = NDI_FAILURE; 50386008Syy154373 break; 50396008Syy154373 } 50406008Syy154373 mutex_enter(&acb->acb_mutex); 50416008Syy154373 if (acb->device_map[tgt] & 1 << lun) { 50426008Syy154373 rval = arcmsr_config_lun(acb, tgt, lun, childp); 50436008Syy154373 } 50446008Syy154373 mutex_exit(&acb->acb_mutex); 50456008Syy154373 break; 50466008Syy154373 50476008Syy154373 case BUS_CONFIG_DRIVER: 50486008Syy154373 case BUS_CONFIG_ALL: 50496008Syy154373 for (tgt = 0; tgt < ARCMSR_MAX_TARGETID; tgt++) 50506008Syy154373 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) 50516008Syy154373 if (acb->device_map[tgt] & 1 << lun) 50526008Syy154373 (void) arcmsr_config_lun(acb, tgt, 50536008Syy154373 lun, NULL); 50546008Syy154373 50556008Syy154373 rval = NDI_SUCCESS; 50566008Syy154373 break; 50576008Syy154373 } 50586008Syy154373 if (rval == NDI_SUCCESS) 50596008Syy154373 rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0); 50606008Syy154373 ndi_devi_exit(parent, circ); 50616008Syy154373 return (rval); 50626008Syy154373} 50636008Syy154373