isp_sbus.c revision 289812
119370Spst/*- 219370Spst * Copyright (c) 1997-2006 by Matthew Jacob 319370Spst * All rights reserved. 419370Spst * 519370Spst * Redistribution and use in source and binary forms, with or without 619370Spst * modification, are permitted provided that the following conditions 719370Spst * are met: 819370Spst * 1. Redistributions of source code must retain the above copyright 919370Spst * notice immediately at the beginning of the file, without modification, 1019370Spst * this list of conditions, and the following disclaimer. 1119370Spst * 2. The name of the author may not be used to endorse or promote products 1219370Spst * derived from this software without specific prior written permission. 1319370Spst * 1419370Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1519370Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1619370Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1719370Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1819370Spst * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1919370Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2019370Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2119370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2219370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2319370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2419370Spst * SUCH DAMAGE. 2519370Spst */ 2619370Spst/* 2719370Spst * SBus specific probe and attach routines for Qlogic ISP SCSI adapters. 2819370Spst * FreeBSD Version. 2919370Spst */ 3019370Spst 3119370Spst#include <sys/cdefs.h> 3219370Spst__FBSDID("$FreeBSD: head/sys/dev/isp/isp_sbus.c 289812 2015-10-23 08:26:45Z mav $"); 3319370Spst 3419370Spst#include <sys/param.h> 3519370Spst#include <sys/systm.h> 3619370Spst#include <sys/linker.h> 3719370Spst#include <sys/firmware.h> 3819370Spst#include <sys/bus.h> 3919370Spst#include <sys/kernel.h> 4019370Spst#include <sys/module.h> 4119370Spst#include <sys/resource.h> 4219370Spst 4319370Spst#include <dev/ofw/ofw_bus.h> 4419370Spst#include <dev/ofw/openfirm.h> 4519370Spst 4619370Spst#include <machine/bus.h> 4719370Spst#include <machine/ofw_machdep.h> 4819370Spst#include <machine/resource.h> 4919370Spst#include <sys/rman.h> 5019370Spst#include <sparc64/sbus/sbusvar.h> 5119370Spst 5219370Spst#include <dev/isp/isp_freebsd.h> 5319370Spst 5419370Spststatic uint32_t isp_sbus_rd_reg(ispsoftc_t *, int); 5519370Spststatic void isp_sbus_wr_reg(ispsoftc_t *, int, uint32_t); 5619370Spststatic int isp_sbus_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); 5719370Spststatic int isp_sbus_mbxdma(ispsoftc_t *); 5819370Spststatic int isp_sbus_dmasetup(ispsoftc_t *, XS_T *, void *); 5919370Spst 6019370Spst 6119370Spststatic void isp_sbus_reset0(ispsoftc_t *); 6219370Spststatic void isp_sbus_reset1(ispsoftc_t *); 6319370Spststatic void isp_sbus_dumpregs(ispsoftc_t *, const char *); 6419370Spst 6519370Spststatic struct ispmdvec mdvec = { 6619370Spst isp_sbus_rd_isr, 6719370Spst isp_sbus_rd_reg, 6819370Spst isp_sbus_wr_reg, 6919370Spst isp_sbus_mbxdma, 7019370Spst isp_sbus_dmasetup, 7119370Spst isp_common_dmateardown, 7219370Spst isp_sbus_reset0, 7319370Spst isp_sbus_reset1, 7419370Spst isp_sbus_dumpregs, 7519370Spst NULL, 7619370Spst BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 7719370Spst}; 7819370Spst 7919370Spststatic int isp_sbus_probe (device_t); 8019370Spststatic int isp_sbus_attach (device_t); 8119370Spststatic int isp_sbus_detach (device_t); 8219370Spst 8319370Spst 8419370Spst#define ISP_SBD(isp) ((struct isp_sbussoftc *)isp)->sbus_dev 8519370Spststruct isp_sbussoftc { 8619370Spst ispsoftc_t sbus_isp; 8719370Spst device_t sbus_dev; 8819370Spst struct resource * regs; 8919370Spst void * irq; 9019370Spst int iqd; 9119370Spst int rgd; 9219370Spst void * ih; 9319370Spst int16_t sbus_poff[_NREG_BLKS]; 9419370Spst sdparam sbus_param; 9519370Spst struct isp_spi sbus_spi; 9619370Spst struct ispmdvec sbus_mdvec; 9719370Spst}; 9819370Spst 9919370Spst 10019370Spststatic device_method_t isp_sbus_methods[] = { 10119370Spst /* Device interface */ 10219370Spst DEVMETHOD(device_probe, isp_sbus_probe), 10319370Spst DEVMETHOD(device_attach, isp_sbus_attach), 10419370Spst DEVMETHOD(device_detach, isp_sbus_detach), 10519370Spst { 0, 0 } 10619370Spst}; 10719370Spst 10819370Spststatic driver_t isp_sbus_driver = { 10919370Spst "isp", isp_sbus_methods, sizeof (struct isp_sbussoftc) 11019370Spst}; 11119370Spststatic devclass_t isp_devclass; 11219370SpstDRIVER_MODULE(isp, sbus, isp_sbus_driver, isp_devclass, 0, 0); 11319370SpstMODULE_DEPEND(isp, cam, 1, 1, 1); 11419370SpstMODULE_DEPEND(isp, firmware, 1, 1, 1); 11519370Spst 11619370Spststatic int 11719370Spstisp_sbus_probe(device_t dev) 11819370Spst{ 11919370Spst int found = 0; 12019370Spst const char *name = ofw_bus_get_name(dev); 12119370Spst if (strcmp(name, "SUNW,isp") == 0 || 12219370Spst strcmp(name, "QLGC,isp") == 0 || 12319370Spst strcmp(name, "ptisp") == 0 || 12419370Spst strcmp(name, "PTI,ptisp") == 0) { 12519370Spst found++; 12619370Spst } 12719370Spst if (!found) 12819370Spst return (ENXIO); 12919370Spst 13019370Spst if (isp_announced == 0 && bootverbose) { 13119370Spst printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 13219370Spst "Core Version %d.%d\n", 13319370Spst ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 13419370Spst ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 13519370Spst isp_announced++; 13619370Spst } 13719370Spst return (0); 13819370Spst} 13919370Spst 14019370Spststatic int 14119370Spstisp_sbus_attach(device_t dev) 14219370Spst{ 14319370Spst int tval, isp_debug, role, ispburst, default_id; 14419370Spst struct isp_sbussoftc *sbs; 14519370Spst ispsoftc_t *isp = NULL; 14619370Spst int locksetup = 0; 14719370Spst int ints_setup = 0; 14819370Spst 14919370Spst sbs = device_get_softc(dev); 15019370Spst if (sbs == NULL) { 15119370Spst device_printf(dev, "cannot get softc\n"); 15219370Spst return (ENOMEM); 15319370Spst } 15419370Spst 15519370Spst sbs->sbus_dev = dev; 15619370Spst sbs->sbus_mdvec = mdvec; 15719370Spst 15819370Spst /* 15919370Spst * Figure out if we're supposed to skip this one. 16019370Spst * If we are, we actually go to ISP_ROLE_NONE. 16119370Spst */ 16219370Spst 16319370Spst tval = 0; 16419370Spst if (resource_int_value(device_get_name(dev), device_get_unit(dev), 16519370Spst "disable", &tval) == 0 && tval) { 16619370Spst device_printf(dev, "device is disabled\n"); 16719370Spst /* but return 0 so the !$)$)*!$*) unit isn't reused */ 16819370Spst return (0); 16919370Spst } 17019370Spst 17119370Spst role = 0; 17219370Spst if (resource_int_value(device_get_name(dev), device_get_unit(dev), 17319370Spst "role", &role) == 0 && 17419370Spst ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) { 17519370Spst device_printf(dev, "setting role to 0x%x\n", role); 17619370Spst } else { 17719370Spst role = ISP_DEFAULT_ROLES; 17819370Spst } 17919370Spst 18019370Spst sbs->irq = sbs->regs = NULL; 18119370Spst sbs->rgd = sbs->iqd = 0; 18219370Spst 18319370Spst sbs->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sbs->rgd, 18419370Spst RF_ACTIVE); 18519370Spst if (sbs->regs == NULL) { 18619370Spst device_printf(dev, "unable to map registers\n"); 18719370Spst goto bad; 18819370Spst } 18919370Spst 19019370Spst sbs->sbus_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 19119370Spst sbs->sbus_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = SBUS_MBOX_REGS_OFF; 19219370Spst sbs->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF; 19319370Spst sbs->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF; 19419370Spst sbs->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 19519370Spst isp = &sbs->sbus_isp; 19619370Spst isp->isp_bus_tag = rman_get_bustag(sbs->regs); 19719370Spst isp->isp_bus_handle = rman_get_bushandle(sbs->regs); 19819370Spst isp->isp_mdvec = &sbs->sbus_mdvec; 19919370Spst isp->isp_bustype = ISP_BT_SBUS; 20019370Spst isp->isp_type = ISP_HA_SCSI_UNKNOWN; 20119370Spst isp->isp_param = &sbs->sbus_param; 20219370Spst isp->isp_osinfo.pc.ptr = &sbs->sbus_spi; 20319370Spst isp->isp_revision = 0; /* XXX */ 20419370Spst isp->isp_dev = dev; 20519370Spst isp->isp_nchan = 1; 20619370Spst ISP_SET_PC(isp, 0, def_role, role); 20719370Spst 20819370Spst /* 20919370Spst * Get the clock frequency and convert it from HZ to MHz, 21019370Spst * rounding up. This defaults to 25MHz if there isn't a 21119370Spst * device specific one in the OFW device tree. 21219370Spst */ 21319370Spst sbs->sbus_mdvec.dv_clock = (sbus_get_clockfreq(dev) + 500000)/1000000; 21419370Spst 21519370Spst /* 21619370Spst * Now figure out what the proper burst sizes, etc., to use. 21719370Spst * Unfortunately, there is no ddi_dma_burstsizes here which 21819370Spst * walks up the tree finding the limiting burst size node (if 21919370Spst * any). We just use what's here for isp. 22019370Spst */ 22119370Spst ispburst = sbus_get_burstsz(dev); 22219370Spst if (ispburst == 0) { 22319370Spst ispburst = SBUS_BURST_32 - 1; 22419370Spst } 22519370Spst sbs->sbus_mdvec.dv_conf1 = 0; 22619370Spst if (ispburst & (1 << 5)) { 22719370Spst sbs->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_32; 22819370Spst } else if (ispburst & (1 << 4)) { 22919370Spst sbs->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_16; 23019370Spst } else if (ispburst & (1 << 3)) { 23119370Spst sbs->sbus_mdvec.dv_conf1 = 23219370Spst BIU_SBUS_CONF1_BURST8 | BIU_SBUS_CONF1_FIFO_8; 23319370Spst } 23419370Spst if (sbs->sbus_mdvec.dv_conf1) { 23519370Spst sbs->sbus_mdvec.dv_conf1 |= BIU_BURST_ENABLE; 23619370Spst } 23719370Spst 23819370Spst /* 23919370Spst * We don't trust NVRAM on SBus cards 24019370Spst */ 24119370Spst isp->isp_confopts |= ISP_CFG_NONVRAM; 24219370Spst 24319370Spst /* 24419370Spst * Mark things if we're a PTI SBus adapter. 24519370Spst */ 24619370Spst if (strcmp("PTI,ptisp", ofw_bus_get_name(dev)) == 0 || 24719370Spst strcmp("ptisp", ofw_bus_get_name(dev)) == 0) { 24819370Spst SDPARAM(isp, 0)->isp_ptisp = 1; 24919370Spst } 25019370Spst 25119370Spst isp->isp_osinfo.fw = firmware_get("isp_1000"); 25219370Spst if (isp->isp_osinfo.fw) { 25319370Spst union { 25419370Spst const void *cp; 25519370Spst uint16_t *sp; 25619370Spst } stupid; 25719370Spst stupid.cp = isp->isp_osinfo.fw->data; 25819370Spst isp->isp_mdvec->dv_ispfw = stupid.sp; 25919370Spst } 26019370Spst 26119370Spst tval = 0; 26219370Spst if (resource_int_value(device_get_name(dev), device_get_unit(dev), 26319370Spst "fwload_disable", &tval) == 0 && tval != 0) { 26419370Spst isp->isp_confopts |= ISP_CFG_NORELOAD; 26519370Spst } 26619370Spst 26719370Spst default_id = -1; 26819370Spst if (resource_int_value(device_get_name(dev), device_get_unit(dev), 26919370Spst "iid", &tval) == 0) { 27019370Spst default_id = tval; 27119370Spst isp->isp_confopts |= ISP_CFG_OWNLOOPID; 27219370Spst } 27319370Spst if (default_id == -1) { 27419370Spst default_id = OF_getscsinitid(dev); 27519370Spst } 27619370Spst ISP_SPI_PC(isp, 0)->iid = default_id; 27719370Spst 27819370Spst isp_debug = 0; 27919370Spst (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 28019370Spst "debug", &isp_debug); 28119370Spst 28219370Spst /* Make sure the lock is set up. */ 28319370Spst mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); 28419370Spst locksetup++; 28519370Spst 28619370Spst sbs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sbs->iqd, 28719370Spst RF_ACTIVE | RF_SHAREABLE); 28819370Spst if (sbs->irq == NULL) { 28919370Spst device_printf(dev, "could not allocate interrupt\n"); 29019370Spst goto bad; 29119370Spst } 29219370Spst 29319370Spst if (isp_setup_intr(dev, sbs->irq, ISP_IFLAGS, NULL, isp_platform_intr, 29419370Spst isp, &sbs->ih)) { 29519370Spst device_printf(dev, "could not setup interrupt\n"); 29619370Spst goto bad; 29719370Spst } 29819370Spst ints_setup++; 29919370Spst 30019370Spst /* 30119370Spst * Set up logging levels. 30219370Spst */ 30319370Spst if (isp_debug) { 30419370Spst isp->isp_dblev = isp_debug; 30519370Spst } else { 30619370Spst isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 30719370Spst } 30819370Spst if (bootverbose) { 30919370Spst isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 31019370Spst } 31119370Spst 31219370Spst /* 31319370Spst * Make sure we're in reset state. 31419370Spst */ 31519370Spst ISP_LOCK(isp); 31619370Spst isp_reset(isp, 1); 31719370Spst if (isp->isp_state != ISP_RESETSTATE) { 31819370Spst isp_uninit(isp); 31919370Spst ISP_UNLOCK(isp); 32019370Spst goto bad; 32119370Spst } 32219370Spst isp_init(isp); 32319370Spst if (isp->isp_state == ISP_INITSTATE) { 32419370Spst isp->isp_state = ISP_RUNSTATE; 32519370Spst } 32619370Spst ISP_UNLOCK(isp); 32719370Spst if (isp_attach(isp)) { 32819370Spst ISP_LOCK(isp); 32919370Spst isp_uninit(isp); 33019370Spst ISP_UNLOCK(isp); 33119370Spst goto bad; 33219370Spst } 33319370Spst return (0); 33419370Spst 33519370Spstbad: 33619370Spst 33719370Spst if (sbs && ints_setup) { 33819370Spst (void) bus_teardown_intr(dev, sbs->irq, sbs->ih); 33919370Spst } 34019370Spst 34119370Spst if (sbs && sbs->irq) { 34219370Spst bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq); 34319370Spst } 34419370Spst 34519370Spst if (locksetup && isp) { 34619370Spst mtx_destroy(&isp->isp_osinfo.lock); 34719370Spst } 34819370Spst 34919370Spst if (sbs->regs) { 35019370Spst (void) bus_release_resource(dev, SYS_RES_MEMORY, sbs->rgd, 35119370Spst sbs->regs); 35219370Spst } 35319370Spst return (ENXIO); 35419370Spst} 35519370Spst 35619370Spststatic int 35719370Spstisp_sbus_detach(device_t dev) 35819370Spst{ 35919370Spst struct isp_sbussoftc *sbs; 36019370Spst ispsoftc_t *isp; 36119370Spst int status; 36219370Spst 36319370Spst sbs = device_get_softc(dev); 36419370Spst if (sbs == NULL) { 36519370Spst return (ENXIO); 36619370Spst } 36719370Spst isp = (ispsoftc_t *) sbs; 36819370Spst status = isp_detach(isp); 36919370Spst if (status) 37019370Spst return (status); 37119370Spst ISP_LOCK(isp); 37219370Spst isp_uninit(isp); 37319370Spst if (sbs->ih) { 37419370Spst (void) bus_teardown_intr(dev, sbs->irq, sbs->ih); 37519370Spst } 37619370Spst ISP_UNLOCK(isp); 37719370Spst mtx_destroy(&isp->isp_osinfo.lock); 37819370Spst (void) bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq); 37919370Spst (void) bus_release_resource(dev, SYS_RES_MEMORY, sbs->rgd, sbs->regs); 38019370Spst return (0); 38119370Spst} 38219370Spst 38319370Spst#define IspVirt2Off(a, x) \ 38419370Spst (((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \ 38519370Spst _BLK_REG_SHFT] + ((x) & 0xff)) 38619370Spst 38719370Spst#define BXR2(sbc, off) \ 38819370Spst bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, off) 38919370Spst 39019370Spststatic int 39119370Spstisp_sbus_rd_isr(ispsoftc_t *isp, uint16_t *isrp, uint16_t *semap, uint16_t *info) 39219370Spst{ 39319370Spst uint16_t isr, sema; 39419370Spst 39519370Spst isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR)); 39619370Spst sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA)); 39719370Spst isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); 39819370Spst isr &= INT_PENDING_MASK(isp); 39919370Spst sema &= BIU_SEMA_LOCK; 40019370Spst if (isr == 0 && sema == 0) { 40119370Spst return (0); 40219370Spst } 40319370Spst *isrp = isr; 40419370Spst if ((*semap = sema) != 0) 40519370Spst *info = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0)); 40619370Spst return (1); 40719370Spst} 40819370Spst 40919370Spststatic uint32_t 41019370Spstisp_sbus_rd_reg(ispsoftc_t *isp, int regoff) 41119370Spst{ 41219370Spst uint16_t rval; 41319370Spst struct isp_sbussoftc *sbs = (struct isp_sbussoftc *) isp; 41419370Spst int offset = sbs->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 41519370Spst offset += (regoff & 0xff); 41619370Spst rval = bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, offset); 41719370Spst isp_prt(isp, ISP_LOGDEBUG3, 41819370Spst "isp_sbus_rd_reg(off %x) = %x", regoff, rval); 41919370Spst return (rval); 42019370Spst} 42119370Spst 42219370Spststatic void 42319370Spstisp_sbus_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val) 42419370Spst{ 42519370Spst struct isp_sbussoftc *sbs = (struct isp_sbussoftc *) isp; 42619370Spst int offset = sbs->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 42719370Spst offset += (regoff & 0xff); 42819370Spst isp_prt(isp, ISP_LOGDEBUG3, 42919370Spst "isp_sbus_wr_reg(off %x) = %x", regoff, val); 43019370Spst bus_space_write_2(isp->isp_bus_tag, isp->isp_bus_handle, offset, val); 43119370Spst MEMORYBARRIER(isp, SYNC_REG, offset, 2, -1); 43219370Spst} 43319370Spst 43419370Spststruct imush { 43519370Spst ispsoftc_t *isp; 43619370Spst int error; 43719370Spst}; 43819370Spst 43919370Spststatic void imc(void *, bus_dma_segment_t *, int, int); 44019370Spst 44119370Spststatic void 44219370Spstimc(void *arg, bus_dma_segment_t *segs, int nseg, int error) 44319370Spst{ 44419370Spst struct imush *imushp = (struct imush *) arg; 44519370Spst if (error) { 44619370Spst imushp->error = error; 44719370Spst } else { 44819370Spst ispsoftc_t *isp =imushp->isp; 44919370Spst bus_addr_t addr = segs->ds_addr; 45019370Spst 45119370Spst isp->isp_rquest_dma = addr; 45219370Spst addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 45319370Spst isp->isp_result_dma = addr; 45419370Spst } 45519370Spst} 45619370Spst 45719370Spststatic int 45819370Spstisp_sbus_mbxdma(ispsoftc_t *isp) 45919370Spst{ 46019370Spst caddr_t base; 46119370Spst uint32_t len; 46219370Spst int i, error; 46319370Spst struct imush im; 46419370Spst 46519370Spst /* 46619370Spst * Already been here? If so, leave... 46719370Spst */ 46819370Spst if (isp->isp_rquest) { 46919370Spst return (0); 47019370Spst } 47119370Spst 47219370Spst ISP_UNLOCK(isp); 47319370Spst 47419370Spst len = sizeof (struct isp_pcmd) * isp->isp_maxcmds; 47519370Spst isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *) 47619370Spst malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 47719370Spst if (isp->isp_osinfo.pcmd_pool == NULL) { 47819370Spst isp_prt(isp, ISP_LOGERR, "cannot alloc pcmd pool"); 47919370Spst ISP_LOCK(isp); 48019370Spst return (1); 48119370Spst } 48219370Spst 48319370Spst len = sizeof (isp_hdl_t *) * isp->isp_maxcmds; 48419370Spst isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 48519370Spst if (isp->isp_xflist == NULL) { 48619370Spst isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 48719370Spst ISP_LOCK(isp); 48819370Spst return (1); 48919370Spst } 49019370Spst for (len = 0; len < isp->isp_maxcmds - 1; len++) { 49119370Spst isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1]; 49219370Spst } 49319370Spst isp->isp_xffree = isp->isp_xflist; 49419370Spst len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 49519370Spst 49619370Spst if (isp_dma_tag_create(BUS_DMA_ROOTARG(ISP_SBD(isp)), 1, 49719370Spst BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT, 49819370Spst BUS_SPACE_MAXADDR_32BIT, NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, 49919370Spst ISP_NSEG_MAX, BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.dmat)) { 50019370Spst isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); 50119370Spst free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); 50219370Spst free(isp->isp_xflist, M_DEVBUF); 50319370Spst ISP_LOCK(isp); 50419370Spst return(1); 50519370Spst } 50619370Spst 50719370Spst /* 50819370Spst * Allocate and map the request, result queues, plus FC scratch area. 50919370Spst */ 51019370Spst len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 51119370Spst len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 51219370Spst 51319370Spst if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, 51419370Spst BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT, 51519370Spst BUS_SPACE_MAXADDR_32BIT, NULL, NULL, len, 1, 51619370Spst BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.cdmat)) { 51719370Spst isp_prt(isp, ISP_LOGERR, 51819370Spst "cannot create a dma tag for control spaces"); 51919370Spst free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); 52019370Spst free(isp->isp_xflist, M_DEVBUF); 52119370Spst ISP_LOCK(isp); 52219370Spst return (1); 52319370Spst } 52419370Spst 52519370Spst if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 52619370Spst &isp->isp_osinfo.cdmap) != 0) { 52719370Spst isp_prt(isp, ISP_LOGERR, 52819370Spst "cannot allocate %d bytes of CCB memory", len); 52919370Spst bus_dma_tag_destroy(isp->isp_osinfo.cdmat); 53019370Spst free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); 53119370Spst free(isp->isp_xflist, M_DEVBUF); 53219370Spst ISP_LOCK(isp); 53319370Spst return (1); 53419370Spst } 53519370Spst 53619370Spst for (i = 0; i < isp->isp_maxcmds; i++) { 53719370Spst struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i]; 53819370Spst error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap); 53919370Spst if (error) { 54019370Spst isp_prt(isp, ISP_LOGERR, 54119370Spst "error %d creating per-cmd DMA maps", error); 54219370Spst while (--i >= 0) { 54319370Spst bus_dmamap_destroy(isp->isp_osinfo.dmat, 54419370Spst isp->isp_osinfo.pcmd_pool[i].dmap); 54519370Spst } 54619370Spst goto bad; 54719370Spst } 54819370Spst callout_init_mtx(&pcmd->wdog, &isp->isp_osinfo.lock, 0); 54919370Spst if (i == isp->isp_maxcmds-1) { 55019370Spst pcmd->next = NULL; 55119370Spst } else { 55219370Spst pcmd->next = &isp->isp_osinfo.pcmd_pool[i+1]; 55319370Spst } 55419370Spst } 55519370Spst isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0]; 55619370Spst 55719370Spst im.isp = isp; 55819370Spst im.error = 0; 55919370Spst bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0); 56019370Spst if (im.error) { 56119370Spst isp_prt(isp, ISP_LOGERR, 56219370Spst "error %d loading dma map for control areas", im.error); 56319370Spst goto bad; 56419370Spst } 56519370Spst 56619370Spst isp->isp_rquest = base; 56719370Spst base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 56819370Spst isp->isp_result = base; 56919370Spst ISP_LOCK(isp); 57019370Spst return (0); 57119370Spst 57219370Spstbad: 57319370Spst bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); 57419370Spst bus_dma_tag_destroy(isp->isp_osinfo.cdmat); 57519370Spst free(isp->isp_xflist, M_DEVBUF); 57619370Spst free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); 57719370Spst isp->isp_rquest = NULL; 57819370Spst ISP_LOCK(isp); 57919370Spst return (1); 58019370Spst} 58119370Spst 58219370Spsttypedef struct { 58319370Spst ispsoftc_t *isp; 58419370Spst void *cmd_token; 58519370Spst void *rq; /* original request */ 58619370Spst int error; 58719370Spst bus_size_t mapsize; 58819370Spst} mush_t; 58919370Spst 59019370Spst#define MUSHERR_NOQENTRIES -2 59119370Spst 59219370Spststatic void dma2(void *, bus_dma_segment_t *, int, int); 59319370Spst 59419370Spststatic void 59519370Spstdma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 59619370Spst{ 59719370Spst mush_t *mp; 59819370Spst ispsoftc_t *isp; 59919370Spst struct ccb_scsiio *csio; 60019370Spst isp_ddir_t ddir; 60119370Spst ispreq_t *rq; 60219370Spst 60319370Spst mp = (mush_t *) arg; 60419370Spst if (error) { 60519370Spst mp->error = error; 60619370Spst return; 60719370Spst } 60819370Spst csio = mp->cmd_token; 60919370Spst isp = mp->isp; 61019370Spst rq = mp->rq; 61119370Spst if (nseg) { 61219370Spst if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 61319370Spst bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); 61419370Spst ddir = ISP_FROM_DEVICE; 61519370Spst } else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 61619370Spst bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); 61719370Spst ddir = ISP_TO_DEVICE; 61819370Spst } else { 61919370Spst ddir = ISP_NOXFR; 62019370Spst } 62119370Spst } else { 62219370Spst dm_segs = NULL; 62319370Spst nseg = 0; 62419370Spst ddir = ISP_NOXFR; 62519370Spst } 62619370Spst 62719370Spst if (isp_send_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir, NULL) != CMD_QUEUED) { 62819370Spst mp->error = MUSHERR_NOQENTRIES; 62919370Spst } 63019370Spst} 63119370Spst 63219370Spststatic int 63319370Spstisp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff) 63419370Spst{ 63519370Spst mush_t mush, *mp; 63619370Spst void (*eptr)(void *, bus_dma_segment_t *, int, int); 63719370Spst int error; 63819370Spst 63919370Spst mp = &mush; 64019370Spst mp->isp = isp; 64119370Spst mp->cmd_token = csio; 64219370Spst mp->rq = ff; 64319370Spst mp->error = 0; 64419370Spst mp->mapsize = 0; 64519370Spst 64619370Spst eptr = dma2; 64719370Spst 64819370Spst error = bus_dmamap_load_ccb(isp->isp_osinfo.dmat, 64919370Spst PISP_PCMD(csio)->dmap, (union ccb *)csio, eptr, mp, 0); 65019370Spst if (error == EINPROGRESS) { 65119370Spst bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); 65219370Spst mp->error = EINVAL; 65319370Spst isp_prt(isp, ISP_LOGERR, 65419370Spst "deferred dma allocation not supported"); 65519370Spst } else if (error && mp->error == 0) { 65619370Spst#ifdef DIAGNOSTIC 65719370Spst isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error); 65819370Spst#endif 65919370Spst mp->error = error; 66019370Spst } 66119370Spst if (mp->error) { 66219370Spst int retval = CMD_COMPLETE; 66319370Spst if (mp->error == MUSHERR_NOQENTRIES) { 66419370Spst retval = CMD_EAGAIN; 66519370Spst } else if (mp->error == EFBIG) { 66619370Spst XS_SETERR(csio, CAM_REQ_TOO_BIG); 66719370Spst } else if (mp->error == EINVAL) { 66819370Spst XS_SETERR(csio, CAM_REQ_INVALID); 66919370Spst } else { 67019370Spst XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 67119370Spst } 67219370Spst return (retval); 67319370Spst } 67419370Spst return (CMD_QUEUED); 67519370Spst} 67619370Spst 67719370Spststatic void 67819370Spstisp_sbus_reset0(ispsoftc_t *isp) 67919370Spst{ 68019370Spst ISP_DISABLE_INTS(isp); 68119370Spst} 68219370Spst 68319370Spststatic void 68419370Spstisp_sbus_reset1(ispsoftc_t *isp) 68519370Spst{ 68619370Spst ISP_ENABLE_INTS(isp); 68719370Spst} 68819370Spst 68919370Spststatic void 69019370Spstisp_sbus_dumpregs(ispsoftc_t *isp, const char *msg) 69119370Spst{ 69219370Spst if (msg) 69319370Spst printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 69419370Spst else 69519370Spst printf("%s:\n", device_get_nameunit(isp->isp_dev)); 69619370Spst printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 69719370Spst printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 69819370Spst ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 69919370Spst printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 70019370Spst 70119370Spst 70219370Spst ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 70319370Spst printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 70419370Spst ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 70519370Spst ISP_READ(isp, CDMA_FIFO_STS)); 70619370Spst printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 70719370Spst ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 70819370Spst ISP_READ(isp, DDMA_FIFO_STS)); 70919370Spst printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 71019370Spst ISP_READ(isp, SXP_INTERRUPT), 71119370Spst ISP_READ(isp, SXP_GROSS_ERR), 71219370Spst ISP_READ(isp, SXP_PINS_CTRL)); 71319370Spst ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 71419370Spst printf(" mbox regs: %x %x %x %x %x\n", 71519370Spst ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 71619370Spst ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 71719370Spst ISP_READ(isp, OUTMAILBOX4)); 71819370Spst} 71919370Spst