1139749Simp/*- 239219Sgibbs * CAM SCSI device driver for the Adaptec 174X SCSI Host adapter 339219Sgibbs * 439219Sgibbs * Copyright (c) 1998 Justin T. Gibbs 539219Sgibbs * All rights reserved. 639219Sgibbs * 739219Sgibbs * Redistribution and use in source and binary forms, with or without 839219Sgibbs * modification, are permitted provided that the following conditions 939219Sgibbs * are met: 1039219Sgibbs * 1. Redistributions of source code must retain the above copyright 1139219Sgibbs * notice immediately at the beginning of the file, without modification, 1239219Sgibbs * this list of conditions, and the following disclaimer. 1339219Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439219Sgibbs * derived from this software without specific prior written permission. 1539219Sgibbs * 1639219Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739219Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839219Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939219Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039219Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139219Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239219Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339219Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439219Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539219Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639219Sgibbs * SUCH DAMAGE. 2739219Sgibbs * 2850477Speter * $FreeBSD$ 2939219Sgibbs */ 3039219Sgibbs 3139219Sgibbs#include <sys/param.h> 32241590Sjhb#include <sys/conf.h> 3339219Sgibbs#include <sys/systm.h> 3439219Sgibbs#include <sys/kernel.h> 3539219Sgibbs#include <sys/malloc.h> 3645791Speter#include <sys/module.h> 37117126Sscottl#include <sys/lock.h> 38117126Sscottl#include <sys/mutex.h> 3945791Speter#include <sys/bus.h> 4039219Sgibbs 4139219Sgibbs#include <machine/bus.h> 4245791Speter#include <machine/resource.h> 4345791Speter#include <sys/rman.h> 4439219Sgibbs 4539219Sgibbs#include <cam/cam.h> 4639219Sgibbs#include <cam/cam_ccb.h> 4739219Sgibbs#include <cam/cam_sim.h> 4839219Sgibbs#include <cam/cam_xpt_sim.h> 4939219Sgibbs#include <cam/cam_debug.h> 5039219Sgibbs 5139219Sgibbs#include <cam/scsi/scsi_message.h> 5239219Sgibbs 5355953Speter#include <dev/eisa/eisaconf.h> 5439219Sgibbs 5555953Speter#include <dev/ahb/ahbreg.h> 5639219Sgibbs 5739219Sgibbs#define ccb_ecb_ptr spriv_ptr0 5839219Sgibbs#define ccb_ahb_ptr spriv_ptr1 5939219Sgibbs 6039219Sgibbs#define ahb_inb(ahb, port) \ 61241590Sjhb bus_read_1((ahb)->res, port) 6239219Sgibbs 6339219Sgibbs#define ahb_inl(ahb, port) \ 64241590Sjhb bus_read_4((ahb)->res, port) 6539219Sgibbs 6639219Sgibbs#define ahb_outb(ahb, port, value) \ 67241590Sjhb bus_write_1((ahb)->res, port, value) 6839219Sgibbs 6939219Sgibbs#define ahb_outl(ahb, port, value) \ 70241590Sjhb bus_write_4((ahb)->res, port, value) 7139219Sgibbs 7239219Sgibbsstatic const char *ahbmatch(eisa_id_t type); 73170872Sscottlstatic struct ahb_softc *ahballoc(device_t dev, struct resource *res); 7439219Sgibbsstatic void ahbfree(struct ahb_softc *ahb); 7539219Sgibbsstatic int ahbreset(struct ahb_softc *ahb); 7639219Sgibbsstatic void ahbmapecbs(void *arg, bus_dma_segment_t *segs, 7739219Sgibbs int nseg, int error); 7839219Sgibbsstatic int ahbxptattach(struct ahb_softc *ahb); 7939219Sgibbsstatic void ahbhandleimmed(struct ahb_softc *ahb, 8039219Sgibbs u_int32_t mbox, u_int intstat); 8139219Sgibbsstatic void ahbcalcresid(struct ahb_softc *ahb, 8239219Sgibbs struct ecb *ecb, union ccb *ccb); 8339219Sgibbsstatic __inline void ahbdone(struct ahb_softc *ahb, u_int32_t mbox, 8439219Sgibbs u_int intstat); 8539219Sgibbsstatic void ahbintr(void *arg); 86241590Sjhbstatic void ahbintr_locked(struct ahb_softc *ahb); 8739219Sgibbsstatic bus_dmamap_callback_t ahbexecuteecb; 8839219Sgibbsstatic void ahbaction(struct cam_sim *sim, union ccb *ccb); 8939219Sgibbsstatic void ahbpoll(struct cam_sim *sim); 9039219Sgibbs 9139219Sgibbs/* Our timeout handler */ 92241590Sjhbstatic void ahbtimeout(void *arg); 9339219Sgibbs 9439219Sgibbsstatic __inline struct ecb* ahbecbget(struct ahb_softc *ahb); 9539219Sgibbsstatic __inline void ahbecbfree(struct ahb_softc* ahb, 9639219Sgibbs struct ecb* ecb); 9739219Sgibbsstatic __inline u_int32_t ahbecbvtop(struct ahb_softc *ahb, 9839219Sgibbs struct ecb *ecb); 9939219Sgibbsstatic __inline struct ecb* ahbecbptov(struct ahb_softc *ahb, 10039219Sgibbs u_int32_t ecb_addr); 10139219Sgibbsstatic __inline u_int32_t ahbstatuspaddr(u_int32_t ecb_paddr); 10239219Sgibbsstatic __inline u_int32_t ahbsensepaddr(u_int32_t ecb_paddr); 10339219Sgibbsstatic __inline u_int32_t ahbsgpaddr(u_int32_t ecb_paddr); 10439219Sgibbsstatic __inline void ahbqueuembox(struct ahb_softc *ahb, 10539219Sgibbs u_int32_t mboxval, 10639219Sgibbs u_int attn_code); 10739219Sgibbs 10839219Sgibbsstatic __inline struct ecb* 10939219Sgibbsahbecbget(struct ahb_softc *ahb) 11039219Sgibbs{ 11139219Sgibbs struct ecb* ecb; 11239219Sgibbs 113241590Sjhb if (!dumping) 114241590Sjhb mtx_assert(&ahb->lock, MA_OWNED); 11539219Sgibbs if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL) 11639219Sgibbs SLIST_REMOVE_HEAD(&ahb->free_ecbs, links); 11739219Sgibbs 11839219Sgibbs return (ecb); 11939219Sgibbs} 12039219Sgibbs 12139219Sgibbsstatic __inline void 12239219Sgibbsahbecbfree(struct ahb_softc* ahb, struct ecb* ecb) 12339219Sgibbs{ 12439219Sgibbs 125241590Sjhb if (!dumping) 126241590Sjhb mtx_assert(&ahb->lock, MA_OWNED); 12739219Sgibbs ecb->state = ECB_FREE; 12839219Sgibbs SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links); 12939219Sgibbs} 13039219Sgibbs 13139219Sgibbsstatic __inline u_int32_t 13239219Sgibbsahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb) 13339219Sgibbs{ 13439219Sgibbs return (ahb->ecb_physbase 13539219Sgibbs + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array)); 13639219Sgibbs} 13739219Sgibbs 13839219Sgibbsstatic __inline struct ecb* 13939219Sgibbsahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr) 14039219Sgibbs{ 14139219Sgibbs return (ahb->ecb_array 142118225Sgallatin + ((struct ecb*)(uintptr_t)ecb_addr 143118225Sgallatin - (struct ecb*)(uintptr_t)ahb->ecb_physbase)); 14439219Sgibbs} 14539219Sgibbs 14639219Sgibbsstatic __inline u_int32_t 14739219Sgibbsahbstatuspaddr(u_int32_t ecb_paddr) 14839219Sgibbs{ 14939219Sgibbs return (ecb_paddr + offsetof(struct ecb, status)); 15039219Sgibbs} 15139219Sgibbs 15239219Sgibbsstatic __inline u_int32_t 15339219Sgibbsahbsensepaddr(u_int32_t ecb_paddr) 15439219Sgibbs{ 15539219Sgibbs return (ecb_paddr + offsetof(struct ecb, sense)); 15639219Sgibbs} 15739219Sgibbs 15839219Sgibbsstatic __inline u_int32_t 15939219Sgibbsahbsgpaddr(u_int32_t ecb_paddr) 16039219Sgibbs{ 16139219Sgibbs return (ecb_paddr + offsetof(struct ecb, sg_list)); 16239219Sgibbs} 16339219Sgibbs 16439219Sgibbsstatic __inline void 16539219Sgibbsahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code) 16639219Sgibbs{ 16739219Sgibbs u_int loopmax = 300; 16839219Sgibbs while (--loopmax) { 16939219Sgibbs u_int status; 17039219Sgibbs 17139219Sgibbs status = ahb_inb(ahb, HOSTSTAT); 17243312Sdillon if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY)) 17343316Sgibbs == HOSTSTAT_MBOX_EMPTY) 17439219Sgibbs break; 17539219Sgibbs DELAY(20); 17639219Sgibbs } 17739219Sgibbs if (loopmax == 0) 178241590Sjhb panic("%s: adapter not taking commands\n", 179241590Sjhb device_get_nameunit(ahb->dev)); 18039219Sgibbs 18139219Sgibbs ahb_outl(ahb, MBOXOUT0, mboxval); 18239219Sgibbs ahb_outb(ahb, ATTN, attn_code); 18339219Sgibbs} 18439219Sgibbs 18539219Sgibbsstatic const char * 18639219Sgibbsahbmatch(eisa_id_t type) 18739219Sgibbs{ 18839219Sgibbs switch(type & 0xfffffe00) { 18939219Sgibbs case EISA_DEVICE_ID_ADAPTEC_1740: 19039219Sgibbs return ("Adaptec 174x SCSI host adapter"); 19139219Sgibbs break; 19239219Sgibbs default: 19339219Sgibbs break; 19439219Sgibbs } 19539219Sgibbs return (NULL); 19639219Sgibbs} 19739219Sgibbs 19839219Sgibbsstatic int 19945791Speterahbprobe(device_t dev) 20039219Sgibbs{ 20145791Speter const char *desc; 20239219Sgibbs u_int32_t iobase; 20339219Sgibbs u_int32_t irq; 20445791Speter u_int8_t intdef; 20549360Smdodd int shared; 20639219Sgibbs 20745791Speter desc = ahbmatch(eisa_get_id(dev)); 20845791Speter if (!desc) 20945791Speter return (ENXIO); 21045791Speter device_set_desc(dev, desc); 21139219Sgibbs 21245791Speter iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + 21345791Speter AHB_EISA_SLOT_OFFSET; 21439219Sgibbs 21545791Speter eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE); 21639219Sgibbs 21745791Speter intdef = inb(INTDEF + iobase); 21845791Speter switch (intdef & 0x7) { 21945791Speter case INT9: 22045791Speter irq = 9; 22145791Speter break; 22245791Speter case INT10: 22345791Speter irq = 10; 22445791Speter break; 22545791Speter case INT11: 22645791Speter irq = 11; 22745791Speter break; 22845791Speter case INT12: 22945791Speter irq = 12; 23045791Speter break; 23145791Speter case INT14: 23245791Speter irq = 14; 23345791Speter break; 23445791Speter case INT15: 23545791Speter irq = 15; 23645791Speter break; 23745791Speter default: 23845791Speter printf("Adaptec 174X at slot %d: illegal " 23945791Speter "irq setting %d\n", eisa_get_slot(dev), 24045791Speter (intdef & 0x7)); 24145791Speter irq = 0; 24245791Speter break; 24339219Sgibbs } 24445791Speter if (irq == 0) 24545791Speter return ENXIO; 24645791Speter 24749360Smdodd shared = (inb(INTDEF + iobase) & INTLEVEL) ? 24849360Smdodd EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE; 24945791Speter 25049360Smdodd eisa_add_intr(dev, irq, shared); 25149360Smdodd 25245791Speter return 0; 25339219Sgibbs} 25439219Sgibbs 25539219Sgibbsstatic int 25645791Speterahbattach(device_t dev) 25739219Sgibbs{ 25839219Sgibbs /* 25939219Sgibbs * find unit and check we have that many defined 26039219Sgibbs */ 26139219Sgibbs struct ahb_softc *ahb; 26239219Sgibbs struct ecb* next_ecb; 263241590Sjhb struct resource *io; 264241590Sjhb struct resource *irq; 26549360Smdodd int rid; 26645791Speter void *ih; 26739219Sgibbs 268241590Sjhb irq = NULL; 26945791Speter rid = 0; 270127135Snjl io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 271241590Sjhb if (io == NULL) { 27245791Speter device_printf(dev, "No I/O space?!\n"); 27345791Speter return ENOMEM; 27439219Sgibbs } 27539219Sgibbs 276241590Sjhb ahb = ahballoc(dev, io); 27739219Sgibbs 27839219Sgibbs if (ahbreset(ahb) != 0) 27945791Speter goto error_exit; 28039219Sgibbs 28145791Speter rid = 0; 282127135Snjl irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 283241590Sjhb if (irq == NULL) { 28445791Speter device_printf(dev, "Can't allocate interrupt\n"); 28545791Speter goto error_exit; 28639219Sgibbs } 28739219Sgibbs 28839219Sgibbs /* 28939219Sgibbs * Create our DMA tags. These tags define the kinds of device 29061686Salex * accessible memory allocations and memory mappings we will 29139219Sgibbs * need to perform during normal operation. 29239219Sgibbs */ 29339219Sgibbs /* DMA tag for mapping buffers into device visible space. */ 294232883Sscottl if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(dev), 295112782Smdodd /* alignment */ 1, 296112782Smdodd /* boundary */ 0, 297112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 298112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 299112782Smdodd /* filter */ NULL, 300112782Smdodd /* filterarg */ NULL, 301112782Smdodd /* maxsize */ MAXBSIZE, 302112782Smdodd /* nsegments */ AHB_NSEG, 303112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 304112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 305117126Sscottl /* lockfunc */ busdma_lock_mutex, 306241590Sjhb /* lockarg */ &ahb->lock, 307112782Smdodd &ahb->buffer_dmat) != 0) 30839219Sgibbs goto error_exit; 30939219Sgibbs 31039219Sgibbs ahb->init_level++; 31139219Sgibbs 31239219Sgibbs /* DMA tag for our ccb structures and ha inquiry data */ 313232883Sscottl if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(dev), 314112782Smdodd /* alignment */ 1, 315112782Smdodd /* boundary */ 0, 316112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 317112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 318112782Smdodd /* filter */ NULL, 319112782Smdodd /* filterarg */ NULL, 320112782Smdodd /* maxsize */ (AHB_NECB * 321112782Smdodd sizeof(struct ecb)) 322112782Smdodd + sizeof(*ahb->ha_inq_data), 323112782Smdodd /* nsegments */ 1, 324112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 325112782Smdodd /* flags */ 0, 326241590Sjhb /* lockfunc */ NULL, 327241590Sjhb /* lockarg */ NULL, 328112782Smdodd &ahb->ecb_dmat) != 0) 32939219Sgibbs goto error_exit; 33039219Sgibbs 33139219Sgibbs ahb->init_level++; 33239219Sgibbs 33339219Sgibbs /* Allocation for our ccbs */ 33439219Sgibbs if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array, 33539219Sgibbs BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0) 33639219Sgibbs goto error_exit; 33739219Sgibbs 33839219Sgibbs ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB]; 33939219Sgibbs 34039219Sgibbs ahb->init_level++; 34139219Sgibbs 34239219Sgibbs /* And permanently map them */ 34339219Sgibbs bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap, 34439219Sgibbs ahb->ecb_array, AHB_NSEG * sizeof(struct ecb), 34539219Sgibbs ahbmapecbs, ahb, /*flags*/0); 34639219Sgibbs 34739219Sgibbs ahb->init_level++; 34839219Sgibbs 34939219Sgibbs /* Allocate the buffer dmamaps for each of our ECBs */ 35039219Sgibbs bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb)) 35139219Sgibbs + sizeof(*ahb->ha_inq_data)); 35239219Sgibbs next_ecb = ahb->ecb_array; 35339219Sgibbs while (ahb->num_ecbs < AHB_NECB) { 35439219Sgibbs u_int32_t ecb_paddr; 35539219Sgibbs 35639219Sgibbs if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0, 35739219Sgibbs &next_ecb->dmamap)) 35839219Sgibbs break; 359241590Sjhb callout_init_mtx(&next_ecb->timer, &ahb->lock, 0); 36039219Sgibbs ecb_paddr = ahbecbvtop(ahb, next_ecb); 36139219Sgibbs next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr); 36239219Sgibbs next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr); 36339219Sgibbs ahb->num_ecbs++; 36439219Sgibbs ahbecbfree(ahb, next_ecb); 36539219Sgibbs next_ecb++; 36639219Sgibbs } 36739219Sgibbs 36839219Sgibbs ahb->init_level++; 36939219Sgibbs 37039219Sgibbs /* 37139219Sgibbs * Now that we know we own the resources we need, register 37239219Sgibbs * our bus with the XPT. 37339219Sgibbs */ 37439219Sgibbs if (ahbxptattach(ahb)) 37539219Sgibbs goto error_exit; 37639219Sgibbs 37739219Sgibbs /* Enable our interrupt */ 378241590Sjhb if (bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE, 379241590Sjhb NULL, ahbintr, ahb, &ih) != 0) 380168219Snetchild goto error_exit; 381168219Snetchild 38239219Sgibbs return (0); 38345791Speter 38439219Sgibbserror_exit: 38539219Sgibbs /* 38639219Sgibbs * The board's IRQ line will not be left enabled 387241590Sjhb * if we can't initialize correctly, so its safe 38839219Sgibbs * to release the irq. 38939219Sgibbs */ 39039219Sgibbs ahbfree(ahb); 391241590Sjhb if (irq != NULL) 39245791Speter bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 393241590Sjhb bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 39439219Sgibbs return (-1); 39539219Sgibbs} 39639219Sgibbs 39739219Sgibbsstatic struct ahb_softc * 398170872Sscottlahballoc(device_t dev, struct resource *res) 39939219Sgibbs{ 40039219Sgibbs struct ahb_softc *ahb; 40139219Sgibbs 402241590Sjhb ahb = device_get_softc(dev); 40339219Sgibbs SLIST_INIT(&ahb->free_ecbs); 40439219Sgibbs LIST_INIT(&ahb->pending_ccbs); 405241590Sjhb ahb->res = res; 40639219Sgibbs ahb->disc_permitted = ~0; 40739219Sgibbs ahb->tags_permitted = ~0; 408170872Sscottl ahb->dev = dev; 409241590Sjhb mtx_init(&ahb->lock, "ahb", NULL, MTX_DEF); 41039219Sgibbs 41139219Sgibbs return (ahb); 41239219Sgibbs} 41339219Sgibbs 41439219Sgibbsstatic void 41539219Sgibbsahbfree(struct ahb_softc *ahb) 41639219Sgibbs{ 41739219Sgibbs switch (ahb->init_level) { 41839219Sgibbs default: 41939219Sgibbs case 4: 42039219Sgibbs bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap); 42139219Sgibbs case 3: 42239219Sgibbs bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array, 42339219Sgibbs ahb->ecb_dmamap); 42439219Sgibbs bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap); 42539219Sgibbs case 2: 42639219Sgibbs bus_dma_tag_destroy(ahb->ecb_dmat); 42739219Sgibbs case 1: 42839219Sgibbs bus_dma_tag_destroy(ahb->buffer_dmat); 42939219Sgibbs case 0: 43097208Speter break; 43139219Sgibbs } 432241590Sjhb mtx_destroy(&ahb->lock); 43339219Sgibbs} 43439219Sgibbs 43539219Sgibbs/* 43639219Sgibbs * reset board, If it doesn't respond, return failure 43739219Sgibbs */ 43839219Sgibbsstatic int 43939219Sgibbsahbreset(struct ahb_softc *ahb) 44039219Sgibbs{ 44139219Sgibbs int wait = 1000; /* 1 sec enough? */ 44239219Sgibbs int test; 44339219Sgibbs 44439219Sgibbs if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) { 44539219Sgibbs printf("ahb_reset: Controller not in enhanced mode\n"); 44639219Sgibbs return (-1); 44739219Sgibbs } 44839219Sgibbs 44939219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_HARD_RST); 45039219Sgibbs DELAY(1000); 45139219Sgibbs ahb_outb(ahb, CONTROL, 0); 45239219Sgibbs while (--wait) { 45339219Sgibbs DELAY(1000); 45439219Sgibbs if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0) 45539219Sgibbs break; 45639219Sgibbs } 45739219Sgibbs 45839219Sgibbs if (wait == 0) { 45939219Sgibbs printf("ahbreset: No answer from aha1742 board\n"); 46039219Sgibbs return (-1); 46139219Sgibbs } 46239219Sgibbs if ((test = ahb_inb(ahb, MBOXIN0)) != 0) { 46339219Sgibbs printf("ahb_reset: self test failed, val = 0x%x\n", test); 46439219Sgibbs return (-1); 46539219Sgibbs } 46639219Sgibbs while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) { 46739219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_CLRINT); 46839219Sgibbs DELAY(10000); 46939219Sgibbs } 47039219Sgibbs return (0); 47139219Sgibbs} 47239219Sgibbs 47339219Sgibbsstatic void 47439219Sgibbsahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 47539219Sgibbs{ 47639219Sgibbs struct ahb_softc* ahb; 47739219Sgibbs 47839219Sgibbs ahb = (struct ahb_softc*)arg; 47939219Sgibbs ahb->ecb_physbase = segs->ds_addr; 48039219Sgibbs /* 48139219Sgibbs * Space for adapter inquiry information is on the 48239219Sgibbs * tail of the ecb array. 48339219Sgibbs */ 48439219Sgibbs ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]); 48539219Sgibbs} 48639219Sgibbs 48739219Sgibbsstatic int 48839219Sgibbsahbxptattach(struct ahb_softc *ahb) 48939219Sgibbs{ 49039219Sgibbs struct cam_devq *devq; 49139219Sgibbs struct ecb *ecb; 49239219Sgibbs u_int i; 49339219Sgibbs 494241590Sjhb mtx_lock(&ahb->lock); 495241590Sjhb 496241590Sjhb /* Remember who are we on the scsi bus */ 49739219Sgibbs ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID; 49839219Sgibbs 49939219Sgibbs /* Use extended translation?? */ 50039219Sgibbs ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS; 50139219Sgibbs 50239219Sgibbs /* Fetch adapter inquiry data */ 50339219Sgibbs ecb = ahbecbget(ahb); /* Always succeeds - no outstanding commands */ 50439219Sgibbs ecb->hecb.opcode = ECBOP_READ_HA_INQDATA; 50539219Sgibbs ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY; 50639219Sgibbs ecb->hecb.data_ptr = ahb->ha_inq_physbase; 50739219Sgibbs ecb->hecb.data_len = sizeof(struct ha_inquiry_data); 50839219Sgibbs ecb->hecb.sense_ptr = 0; 50939219Sgibbs ecb->state = ECB_ACTIVE; 51039219Sgibbs 51139219Sgibbs /* Tell the adapter about this command */ 51239219Sgibbs ahbqueuembox(ahb, ahbecbvtop(ahb, ecb), 51339219Sgibbs ATTN_STARTECB|ahb->scsi_id); 51439219Sgibbs 51539219Sgibbs /* Poll for interrupt completion */ 51639219Sgibbs for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) { 517241590Sjhb ahbintr_locked(ahb); 51839219Sgibbs DELAY(1000); 51939219Sgibbs } 52039219Sgibbs 52139219Sgibbs ahb->num_ecbs = MIN(ahb->num_ecbs, 522159105Smjacob ahb->ha_inq_data->scsi_data.spc2_flags); 523241590Sjhb device_printf(ahb->dev, 524241590Sjhb "%.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n", 525241590Sjhb ahb->ha_inq_data->scsi_data.product, 52639219Sgibbs (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential" 52739219Sgibbs : "Single Ended", 52839219Sgibbs ahb->ha_inq_data->scsi_data.revision, 52939219Sgibbs ahb->scsi_id, ahb->num_ecbs); 53039219Sgibbs 53139219Sgibbs /* Restore sense paddr for future CCB clients */ 53239219Sgibbs ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb)); 53339219Sgibbs 53439219Sgibbs ahbecbfree(ahb, ecb); 53539219Sgibbs 53639219Sgibbs /* 53739219Sgibbs * Create the device queue for our SIM. 53839219Sgibbs */ 53939219Sgibbs devq = cam_simq_alloc(ahb->num_ecbs); 540241590Sjhb if (devq == NULL) { 541241590Sjhb mtx_unlock(&ahb->lock); 54239219Sgibbs return (ENOMEM); 543241590Sjhb } 54439219Sgibbs 54539219Sgibbs /* 54639219Sgibbs * Construct our SIM entry 54739219Sgibbs */ 548241590Sjhb ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, 549241590Sjhb device_get_unit(ahb->dev), &ahb->lock, 2, ahb->num_ecbs, devq); 55039219Sgibbs if (ahb->sim == NULL) { 55139219Sgibbs cam_simq_free(devq); 552241590Sjhb mtx_unlock(&ahb->lock); 55339219Sgibbs return (ENOMEM); 55439219Sgibbs } 55539219Sgibbs 556170872Sscottl if (xpt_bus_register(ahb->sim, ahb->dev, 0) != CAM_SUCCESS) { 55739219Sgibbs cam_sim_free(ahb->sim, /*free_devq*/TRUE); 558241590Sjhb mtx_unlock(&ahb->lock); 55939219Sgibbs return (ENXIO); 56039219Sgibbs } 56139219Sgibbs 56239219Sgibbs if (xpt_create_path(&ahb->path, /*periph*/NULL, 56339219Sgibbs cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD, 56439219Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 56539219Sgibbs xpt_bus_deregister(cam_sim_path(ahb->sim)); 56639219Sgibbs cam_sim_free(ahb->sim, /*free_devq*/TRUE); 567241590Sjhb mtx_unlock(&ahb->lock); 56839219Sgibbs return (ENXIO); 56939219Sgibbs } 57039219Sgibbs 57139219Sgibbs /* 57239219Sgibbs * Allow the board to generate interrupts. 57339219Sgibbs */ 57439219Sgibbs ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN); 575241590Sjhb mtx_unlock(&ahb->lock); 57639219Sgibbs 57739219Sgibbs return (0); 57839219Sgibbs} 57939219Sgibbs 58039219Sgibbsstatic void 58139219Sgibbsahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat) 58239219Sgibbs{ 58339219Sgibbs struct ccb_hdr *ccb_h; 58439219Sgibbs u_int target_id; 58539219Sgibbs 58639219Sgibbs if (ahb->immed_cmd == 0) { 587241590Sjhb device_printf(ahb->dev, "Immediate Command complete with no " 588241590Sjhb " pending command\n"); 58939219Sgibbs return; 59039219Sgibbs } 59139219Sgibbs 59239219Sgibbs target_id = intstat & INTSTAT_TARGET_MASK; 59339219Sgibbs 59439219Sgibbs ccb_h = LIST_FIRST(&ahb->pending_ccbs); 59539219Sgibbs while (ccb_h != NULL) { 59639219Sgibbs struct ecb *pending_ecb; 59739219Sgibbs union ccb *ccb; 59839219Sgibbs 59939219Sgibbs pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr; 60039219Sgibbs ccb = pending_ecb->ccb; 60139219Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 60239219Sgibbs if (ccb->ccb_h.target_id == target_id 60339219Sgibbs || target_id == ahb->scsi_id) { 604241590Sjhb callout_stop(&pending_ecb->timer); 60539219Sgibbs LIST_REMOVE(&ccb->ccb_h, sim_links.le); 60639219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) 60739219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, 60839219Sgibbs pending_ecb->dmamap); 60939219Sgibbs if (pending_ecb == ahb->immed_ecb) 61039219Sgibbs ccb->ccb_h.status = 61139219Sgibbs CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ; 61239219Sgibbs else if (target_id == ahb->scsi_id) 61339219Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 61439219Sgibbs else 61539219Sgibbs ccb->ccb_h.status = CAM_BDR_SENT; 61639219Sgibbs ahbecbfree(ahb, pending_ecb); 61739219Sgibbs xpt_done(ccb); 61839219Sgibbs } else if (ahb->immed_ecb != NULL) { 61939219Sgibbs /* Re-instate timeout */ 620241590Sjhb callout_reset(&pending_ecb->timer, 621241590Sjhb (ccb->ccb_h.timeout * hz) / 1000, 622241590Sjhb ahbtimeout, pending_ecb); 62339219Sgibbs } 62439219Sgibbs } 62539219Sgibbs 62639219Sgibbs if (ahb->immed_ecb != NULL) { 62739219Sgibbs ahb->immed_ecb = NULL; 628241590Sjhb device_printf(ahb->dev, "No longer in timeout\n"); 62939219Sgibbs } else if (target_id == ahb->scsi_id) 630241590Sjhb device_printf(ahb->dev, "SCSI Bus Reset Delivered\n"); 63139219Sgibbs else 632241590Sjhb device_printf(ahb->dev, 633241590Sjhb "Bus Device Reset Delivered to target %d\n", target_id); 63439219Sgibbs 63539219Sgibbs ahb->immed_cmd = 0; 63639219Sgibbs} 63739219Sgibbs 63839219Sgibbsstatic void 63939219Sgibbsahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb) 64039219Sgibbs{ 64139219Sgibbs if (ecb->status.data_overrun != 0) { 64239219Sgibbs /* 64339219Sgibbs * Overrun Condition. The hardware doesn't 64439219Sgibbs * provide a meaningful byte count in this case 64539219Sgibbs * (the residual is always 0). Tell the XPT 64639219Sgibbs * layer about the error. 64739219Sgibbs */ 64839219Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 64939219Sgibbs } else { 65039219Sgibbs ccb->csio.resid = ecb->status.resid_count; 65139219Sgibbs 65239219Sgibbs if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) { 65339219Sgibbs /* 65439219Sgibbs * For S/G transfers, the adapter provides a pointer 65539219Sgibbs * to the address in the last S/G element used and a 65639219Sgibbs * residual for that element. So, we need to sum up 65739219Sgibbs * the elements that follow it in order to get a real 65839219Sgibbs * residual number. If we have an overrun, the residual 65939219Sgibbs * reported will be 0 and we already know that all S/G 66039219Sgibbs * segments have been exhausted, so we can skip this 66139219Sgibbs * step. 66239219Sgibbs */ 66339219Sgibbs ahb_sg_t *sg; 66439219Sgibbs int num_sg; 66539219Sgibbs 66639219Sgibbs num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t); 66739219Sgibbs 66839219Sgibbs /* Find the S/G the adapter was working on */ 66939219Sgibbs for (sg = ecb->sg_list; 67039219Sgibbs num_sg != 0 && sg->addr != ecb->status.resid_addr; 67139219Sgibbs num_sg--, sg++) 67239219Sgibbs ; 67339219Sgibbs 67439219Sgibbs /* Skip it */ 67539219Sgibbs num_sg--; 67639219Sgibbs sg++; 67739219Sgibbs 67839219Sgibbs /* Sum the rest */ 67939219Sgibbs for (; num_sg != 0; num_sg--, sg++) 68039219Sgibbs ccb->csio.resid += sg->len; 68139219Sgibbs } 68239219Sgibbs /* Underruns are not errors */ 68339219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 68439219Sgibbs } 68539219Sgibbs} 68639219Sgibbs 68739219Sgibbsstatic void 68839219Sgibbsahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb) 68939219Sgibbs{ 69039219Sgibbs struct hardware_ecb *hecb; 69139219Sgibbs struct ecb_status *status; 69239219Sgibbs 69339219Sgibbs hecb = &ecb->hecb; 69439219Sgibbs status = &ecb->status; 69539219Sgibbs switch (status->ha_status) { 69639219Sgibbs case HS_OK: 69739219Sgibbs ccb->csio.scsi_status = status->scsi_status; 69839219Sgibbs if (status->scsi_status != 0) { 69939219Sgibbs ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 70039219Sgibbs if (status->sense_stored) { 70139219Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 70239219Sgibbs ccb->csio.sense_resid = 70339219Sgibbs ccb->csio.sense_len - status->sense_len; 70439219Sgibbs bcopy(&ecb->sense, &ccb->csio.sense_data, 70539219Sgibbs status->sense_len); 70639219Sgibbs } 70739219Sgibbs } 70839219Sgibbs break; 70939219Sgibbs case HS_TARGET_NOT_ASSIGNED: 71039219Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 71139219Sgibbs break; 71239219Sgibbs case HS_SEL_TIMEOUT: 71339219Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 71439219Sgibbs break; 71539219Sgibbs case HS_DATA_RUN_ERR: 71639219Sgibbs ahbcalcresid(ahb, ecb, ccb); 71739219Sgibbs break; 71839219Sgibbs case HS_UNEXPECTED_BUSFREE: 71939219Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 72039219Sgibbs break; 72139219Sgibbs case HS_INVALID_PHASE: 72239219Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 72339219Sgibbs break; 72439219Sgibbs case HS_REQUEST_SENSE_FAILED: 72539219Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 72639219Sgibbs break; 72739219Sgibbs case HS_TAG_MSG_REJECTED: 72839219Sgibbs { 72939219Sgibbs struct ccb_trans_settings neg; 730163816Smjacob struct ccb_trans_settings_scsi *scsi = &neg.proto_specific.scsi; 73139219Sgibbs 73239219Sgibbs xpt_print_path(ccb->ccb_h.path); 73339219Sgibbs printf("refuses tagged commands. Performing " 73439219Sgibbs "non-tagged I/O\n"); 735163816Smjacob memset(&neg, 0, sizeof (neg)); 736163816Smjacob neg.protocol = PROTO_SCSI; 737163816Smjacob neg.protocol_version = SCSI_REV_2; 738163816Smjacob neg.transport = XPORT_SPI; 739163816Smjacob neg.transport_version = 2; 740163816Smjacob scsi->flags = CTS_SCSI_VALID_TQ; 74139219Sgibbs xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 74239219Sgibbs xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg); 74339219Sgibbs ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id); 74439219Sgibbs ccb->ccb_h.status = CAM_MSG_REJECT_REC; 74539219Sgibbs break; 74639219Sgibbs } 74739219Sgibbs case HS_FIRMWARE_LOAD_REQ: 74839219Sgibbs case HS_HARDWARE_ERR: 74939219Sgibbs /* 75039219Sgibbs * Tell the system that the Adapter 75139219Sgibbs * is no longer functional. 75239219Sgibbs */ 75339219Sgibbs ccb->ccb_h.status = CAM_NO_HBA; 75439219Sgibbs break; 75539219Sgibbs case HS_CMD_ABORTED_HOST: 75639219Sgibbs case HS_CMD_ABORTED_ADAPTER: 75739219Sgibbs case HS_ATN_TARGET_FAILED: 75839219Sgibbs case HS_SCSI_RESET_ADAPTER: 75939219Sgibbs case HS_SCSI_RESET_INCOMING: 76039219Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 76139219Sgibbs break; 76249360Smdodd case HS_INVALID_ECB_PARAM: 763241590Sjhb device_printf(ahb->dev, 764241590Sjhb "opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n", 765241590Sjhb hecb->opcode, hecb->flag_word1, hecb->flag_word2); 76649360Smdodd ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 76749360Smdodd break; 76839219Sgibbs case HS_DUP_TCB_RECEIVED: 76939219Sgibbs case HS_INVALID_OPCODE: 77039219Sgibbs case HS_INVALID_CMD_LINK: 77139219Sgibbs case HS_PROGRAM_CKSUM_ERROR: 772241590Sjhb panic("%s: Can't happen host status %x occurred", 773241590Sjhb device_get_nameunit(ahb->dev), status->ha_status); 77439219Sgibbs break; 77539219Sgibbs } 77639219Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 77739219Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 77839219Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 77939219Sgibbs } 78039219Sgibbs} 78139219Sgibbs 78239219Sgibbsstatic void 78339219Sgibbsahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat) 78439219Sgibbs{ 78539219Sgibbs struct ecb *ecb; 78639219Sgibbs union ccb *ccb; 78739219Sgibbs 78839219Sgibbs ecb = ahbecbptov(ahb, mbox); 78939219Sgibbs 79039219Sgibbs if ((ecb->state & ECB_ACTIVE) == 0) 79139219Sgibbs panic("ecb not active"); 79239219Sgibbs 79339219Sgibbs ccb = ecb->ccb; 79439219Sgibbs 79539219Sgibbs if (ccb != NULL) { 796241590Sjhb callout_stop(&ecb->timer); 79739219Sgibbs LIST_REMOVE(&ccb->ccb_h, sim_links.le); 79839219Sgibbs 79939219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 800115343Sscottl bus_dmasync_op_t op; 80139219Sgibbs 80239219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 80339219Sgibbs op = BUS_DMASYNC_POSTREAD; 80439219Sgibbs else 80539219Sgibbs op = BUS_DMASYNC_POSTWRITE; 80639219Sgibbs bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op); 80739219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap); 80839219Sgibbs } 80939219Sgibbs 81039219Sgibbs if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) { 81139219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 81239219Sgibbs ccb->csio.resid = 0; 81339219Sgibbs } else { 81439219Sgibbs ahbprocesserror(ahb, ecb, ccb); 81539219Sgibbs } 81639219Sgibbs ahbecbfree(ahb, ecb); 81739219Sgibbs xpt_done(ccb); 81839219Sgibbs } else { 81939219Sgibbs /* Non CCB Command */ 82039219Sgibbs if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) { 821241590Sjhb device_printf(ahb->dev, "Command 0%x Failed %x:%x:%x\n", 822241590Sjhb ecb->hecb.opcode, 82339219Sgibbs *((u_int16_t*)&ecb->status), 82439219Sgibbs ecb->status.ha_status, ecb->status.resid_count); 82539219Sgibbs } 82639219Sgibbs /* Client owns this ECB and will release it. */ 82739219Sgibbs } 82839219Sgibbs} 82939219Sgibbs 83039219Sgibbs/* 83139219Sgibbs * Catch an interrupt from the adaptor 83239219Sgibbs */ 83339219Sgibbsstatic void 83439219Sgibbsahbintr(void *arg) 83539219Sgibbs{ 83639219Sgibbs struct ahb_softc *ahb; 837241590Sjhb 838241590Sjhb ahb = arg; 839241590Sjhb mtx_lock(&ahb->lock); 840241590Sjhb ahbintr_locked(ahb); 841241590Sjhb mtx_unlock(&ahb->lock); 842241590Sjhb} 843241590Sjhb 844241590Sjhbstatic void 845241590Sjhbahbintr_locked(struct ahb_softc *ahb) 846241590Sjhb{ 84739219Sgibbs u_int intstat; 84839219Sgibbs u_int32_t mbox; 84939219Sgibbs 85039219Sgibbs while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) { 85139219Sgibbs /* 85239219Sgibbs * Fetch information about this interrupt. 85339219Sgibbs */ 85439219Sgibbs intstat = ahb_inb(ahb, INTSTAT); 85539219Sgibbs mbox = ahb_inl(ahb, MBOXIN0); 85639219Sgibbs 85739219Sgibbs /* 85839219Sgibbs * Reset interrupt latch. 85939219Sgibbs */ 86039219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_CLRINT); 86139219Sgibbs 86239219Sgibbs /* 86339219Sgibbs * Process the completed operation 86439219Sgibbs */ 86539219Sgibbs switch (intstat & INTSTAT_MASK) { 86639219Sgibbs case INTSTAT_ECB_OK: 86739219Sgibbs case INTSTAT_ECB_CMPWRETRY: 86839219Sgibbs case INTSTAT_ECB_CMPWERR: 86939219Sgibbs ahbdone(ahb, mbox, intstat); 87039219Sgibbs break; 87139219Sgibbs case INTSTAT_AEN_OCCURED: 87239219Sgibbs if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) { 87339219Sgibbs /* Bus Reset */ 87439219Sgibbs xpt_print_path(ahb->path); 87539219Sgibbs switch (mbox) { 87639219Sgibbs case HS_SCSI_RESET_ADAPTER: 87739219Sgibbs printf("Host Adapter Initiated " 87839219Sgibbs "Bus Reset occurred\n"); 87939219Sgibbs break; 88039219Sgibbs case HS_SCSI_RESET_INCOMING: 88139219Sgibbs printf("Bus Reset Initiated " 88239219Sgibbs "by another device occurred\n"); 88339219Sgibbs break; 88439219Sgibbs } 88539219Sgibbs /* Notify the XPT */ 88639219Sgibbs xpt_async(AC_BUS_RESET, ahb->path, NULL); 88739219Sgibbs break; 88839219Sgibbs } 88939219Sgibbs printf("Unsupported initiator selection AEN occured\n"); 89039219Sgibbs break; 89139219Sgibbs case INTSTAT_IMMED_OK: 89239219Sgibbs case INTSTAT_IMMED_ERR: 89339219Sgibbs ahbhandleimmed(ahb, mbox, intstat); 89439219Sgibbs break; 89539219Sgibbs case INTSTAT_HW_ERR: 89639219Sgibbs panic("Unrecoverable hardware Error Occurred\n"); 89739219Sgibbs } 89839219Sgibbs } 89939219Sgibbs} 90039219Sgibbs 90139219Sgibbsstatic void 90239219Sgibbsahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 90339219Sgibbs{ 90439219Sgibbs struct ecb *ecb; 90539219Sgibbs union ccb *ccb; 90639219Sgibbs struct ahb_softc *ahb; 90739219Sgibbs u_int32_t ecb_paddr; 90839219Sgibbs 90939219Sgibbs ecb = (struct ecb *)arg; 91039219Sgibbs ccb = ecb->ccb; 91139219Sgibbs ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr; 912241590Sjhb mtx_assert(&ahb->lock, MA_OWNED); 91339219Sgibbs 91439219Sgibbs if (error != 0) { 91539219Sgibbs if (error != EFBIG) 916241590Sjhb device_printf(ahb->dev, 917241590Sjhb "Unexepected error 0x%x returned from " 918241590Sjhb "bus_dmamap_load\n", error); 91939219Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 92039219Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 92139219Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 92239219Sgibbs } 92339219Sgibbs ahbecbfree(ahb, ecb); 92439219Sgibbs xpt_done(ccb); 92539219Sgibbs return; 92639219Sgibbs } 92739219Sgibbs 92839219Sgibbs ecb_paddr = ahbecbvtop(ahb, ecb); 92939219Sgibbs 93039219Sgibbs if (nseg != 0) { 93139219Sgibbs ahb_sg_t *sg; 93239219Sgibbs bus_dma_segment_t *end_seg; 933115343Sscottl bus_dmasync_op_t op; 93439219Sgibbs 93539219Sgibbs end_seg = dm_segs + nseg; 93639219Sgibbs 93739219Sgibbs /* Copy the segments into our SG list */ 93839219Sgibbs sg = ecb->sg_list; 93939219Sgibbs while (dm_segs < end_seg) { 94039219Sgibbs sg->addr = dm_segs->ds_addr; 94139219Sgibbs sg->len = dm_segs->ds_len; 94239219Sgibbs sg++; 94339219Sgibbs dm_segs++; 94439219Sgibbs } 94539219Sgibbs 94639219Sgibbs if (nseg > 1) { 94739219Sgibbs ecb->hecb.flag_word1 |= FW1_SG_ECB; 94839219Sgibbs ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr); 94939219Sgibbs ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg; 95039219Sgibbs } else { 95139219Sgibbs ecb->hecb.data_ptr = ecb->sg_list->addr; 95239219Sgibbs ecb->hecb.data_len = ecb->sg_list->len; 95339219Sgibbs } 95439219Sgibbs 95539219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 95639219Sgibbs/* ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */ 95739219Sgibbs op = BUS_DMASYNC_PREREAD; 95839219Sgibbs } else { 95939219Sgibbs op = BUS_DMASYNC_PREWRITE; 96039219Sgibbs } 96139219Sgibbs /* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */ 96239219Sgibbs 96339219Sgibbs bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op); 96439219Sgibbs 96539219Sgibbs } else { 96639219Sgibbs ecb->hecb.data_ptr = 0; 96739219Sgibbs ecb->hecb.data_len = 0; 96839219Sgibbs } 96939219Sgibbs 97039219Sgibbs /* 97139219Sgibbs * Last time we need to check if this CCB needs to 97239219Sgibbs * be aborted. 97339219Sgibbs */ 97439219Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 97539219Sgibbs if (nseg != 0) 97639219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap); 97739219Sgibbs ahbecbfree(ahb, ecb); 97839219Sgibbs xpt_done(ccb); 97939219Sgibbs return; 98039219Sgibbs } 98139219Sgibbs 98239219Sgibbs ecb->state = ECB_ACTIVE; 98339219Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 98439219Sgibbs LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le); 98539219Sgibbs 98639219Sgibbs /* Tell the adapter about this command */ 98739219Sgibbs ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id); 98839219Sgibbs 989241590Sjhb callout_reset(&ecb->timer, (ccb->ccb_h.timeout * hz) / 1000, ahbtimeout, 990241590Sjhb ecb); 99139219Sgibbs} 99239219Sgibbs 99339219Sgibbsstatic void 99439219Sgibbsahbaction(struct cam_sim *sim, union ccb *ccb) 99539219Sgibbs{ 99639219Sgibbs struct ahb_softc *ahb; 99739219Sgibbs 99839219Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n")); 99939219Sgibbs 100039219Sgibbs ahb = (struct ahb_softc *)cam_sim_softc(sim); 1001241590Sjhb mtx_assert(&ahb->lock, MA_OWNED); 100239219Sgibbs 100339219Sgibbs switch (ccb->ccb_h.func_code) { 100439219Sgibbs /* Common cases first */ 100539219Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 100639219Sgibbs { 100739219Sgibbs struct ecb *ecb; 100839219Sgibbs struct hardware_ecb *hecb; 1009246713Skib int error; 101039219Sgibbs 101139219Sgibbs /* 101239219Sgibbs * get an ecb to use. 101339219Sgibbs */ 101439219Sgibbs if ((ecb = ahbecbget(ahb)) == NULL) { 101539219Sgibbs /* Should never occur */ 101639219Sgibbs panic("Failed to get an ecb"); 101739219Sgibbs } 101839219Sgibbs 101939219Sgibbs /* 102039219Sgibbs * So we can find the ECB when an abort is requested 102139219Sgibbs */ 102239219Sgibbs ecb->ccb = ccb; 102339219Sgibbs ccb->ccb_h.ccb_ecb_ptr = ecb; 102439219Sgibbs ccb->ccb_h.ccb_ahb_ptr = ahb; 102539219Sgibbs 102639219Sgibbs /* 102739219Sgibbs * Put all the arguments for the xfer in the ecb 102839219Sgibbs */ 102939219Sgibbs hecb = &ecb->hecb; 103039219Sgibbs hecb->opcode = ECBOP_INITIATOR_SCSI_CMD; 103139219Sgibbs hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE 103239219Sgibbs | FW1_ERR_STATUS_BLK_ONLY; 103339219Sgibbs hecb->flag_word2 = ccb->ccb_h.target_lun 103439219Sgibbs | FW2_NO_RETRY_ON_BUSY; 103539219Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 103639219Sgibbs hecb->flag_word2 |= FW2_TAG_ENB 103739219Sgibbs | ((ccb->csio.tag_action & 0x3) 103839219Sgibbs << FW2_TAG_TYPE_SHIFT); 103939219Sgibbs } 104039219Sgibbs if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) 104139219Sgibbs hecb->flag_word2 |= FW2_DISABLE_DISC; 104239219Sgibbs hecb->sense_len = ccb->csio.sense_len; 104339219Sgibbs hecb->cdb_len = ccb->csio.cdb_len; 104439219Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 104539219Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 104639219Sgibbs bcopy(ccb->csio.cdb_io.cdb_ptr, 104739219Sgibbs hecb->cdb, hecb->cdb_len); 104839219Sgibbs } else { 104939219Sgibbs /* I guess I could map it in... */ 105039219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 105139219Sgibbs ahbecbfree(ahb, ecb); 105239219Sgibbs xpt_done(ccb); 105339219Sgibbs return; 105439219Sgibbs } 105539219Sgibbs } else { 105639219Sgibbs bcopy(ccb->csio.cdb_io.cdb_bytes, 105739219Sgibbs hecb->cdb, hecb->cdb_len); 105839219Sgibbs } 105939219Sgibbs 1060246713Skib error = bus_dmamap_load_ccb( 1061246713Skib ahb->buffer_dmat, 1062246713Skib ecb->dmamap, 1063246713Skib ccb, 1064246713Skib ahbexecuteecb, 1065246713Skib ecb, /*flags*/0); 1066246713Skib if (error == EINPROGRESS) { 1067246713Skib /* 1068246713Skib * So as to maintain ordering, freeze the controller 1069246713Skib * queue until our mapping is returned. 1070246713Skib */ 1071246713Skib xpt_freeze_simq(ahb->sim, 1); 1072246713Skib ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 107339219Sgibbs } 107439219Sgibbs break; 107539219Sgibbs } 107639219Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 107739219Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 107839219Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 107939219Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 108039219Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 108139219Sgibbs /* XXX Implement */ 108239219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 108339219Sgibbs xpt_done(ccb); 108439219Sgibbs break; 108539219Sgibbs case XPT_SET_TRAN_SETTINGS: 108639219Sgibbs { 108739219Sgibbs ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 108839219Sgibbs xpt_done(ccb); 108939219Sgibbs break; 109039219Sgibbs } 109139219Sgibbs case XPT_GET_TRAN_SETTINGS: 109239219Sgibbs /* Get default/user set transfer settings for the target */ 109339219Sgibbs { 1094163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 1095163816Smjacob u_int target_mask = 0x01 << ccb->ccb_h.target_id; 1096163816Smjacob struct ccb_trans_settings_scsi *scsi = 1097163816Smjacob &cts->proto_specific.scsi; 1098163816Smjacob struct ccb_trans_settings_spi *spi = 1099163816Smjacob &cts->xport_specific.spi; 110039219Sgibbs 1101163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 1102163816Smjacob cts->protocol = PROTO_SCSI; 1103163816Smjacob cts->protocol_version = SCSI_REV_2; 1104163816Smjacob cts->transport = XPORT_SPI; 1105163816Smjacob cts->transport_version = 2; 1106163816Smjacob 1107163816Smjacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1108163816Smjacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 1109163816Smjacob if ((ahb->disc_permitted & target_mask) != 0) 1110163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 1111163816Smjacob if ((ahb->tags_permitted & target_mask) != 0) 1112163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 1113163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1114163816Smjacob spi->sync_period = 25; /* 10MHz */ 1115163816Smjacob 1116163816Smjacob if (spi->sync_period != 0) 1117163816Smjacob spi->sync_offset = 15; 1118163816Smjacob 1119163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 1120163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 1121163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 1122163816Smjacob | CTS_SPI_VALID_DISC; 1123163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 1124163816Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 1125163816Smjacob } else { 1126163816Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1127163816Smjacob } 112839219Sgibbs xpt_done(ccb); 112939219Sgibbs break; 113039219Sgibbs } 113139219Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 113239219Sgibbs { 113339219Sgibbs int i; 113439219Sgibbs 113539219Sgibbs ahb->immed_cmd = IMMED_RESET; 113639219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id); 113739219Sgibbs /* Poll for interrupt completion */ 113844508Sgibbs for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) { 113939219Sgibbs DELAY(1000); 1140241590Sjhb ahbintr_locked(cam_sim_softc(sim)); 114144508Sgibbs } 114239219Sgibbs break; 114339219Sgibbs } 114439219Sgibbs case XPT_CALC_GEOMETRY: 114539219Sgibbs { 1146116351Snjl cam_calc_geometry(&ccb->ccg, ahb->extended_trans); 114739219Sgibbs xpt_done(ccb); 114839219Sgibbs break; 114939219Sgibbs } 115039219Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 115139219Sgibbs { 115239219Sgibbs int i; 115339219Sgibbs 115439219Sgibbs ahb->immed_cmd = IMMED_RESET; 115539219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id); 115639219Sgibbs /* Poll for interrupt completion */ 115739219Sgibbs for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) 115839219Sgibbs DELAY(1000); 115939219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 116039219Sgibbs xpt_done(ccb); 116139219Sgibbs break; 116239219Sgibbs } 116339219Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 116439219Sgibbs /* XXX Implement */ 116539219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 116639219Sgibbs xpt_done(ccb); 116739219Sgibbs break; 116839219Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 116939219Sgibbs { 117039219Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 117139219Sgibbs 117239219Sgibbs cpi->version_num = 1; /* XXX??? */ 117339219Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 117439219Sgibbs cpi->target_sprt = 0; 117539219Sgibbs cpi->hba_misc = 0; 117639219Sgibbs cpi->hba_eng_cnt = 0; 117739219Sgibbs cpi->max_target = 7; 117839219Sgibbs cpi->max_lun = 7; 117939219Sgibbs cpi->initiator_id = ahb->scsi_id; 118039219Sgibbs cpi->bus_id = cam_sim_bus(sim); 118146581Sken cpi->base_transfer_speed = 3300; 118239219Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 118339219Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 118439219Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 118539219Sgibbs cpi->unit_number = cam_sim_unit(sim); 1186163816Smjacob cpi->transport = XPORT_SPI; 1187163816Smjacob cpi->transport_version = 2; 1188163816Smjacob cpi->protocol = PROTO_SCSI; 1189163816Smjacob cpi->protocol_version = SCSI_REV_2; 119039219Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 119139219Sgibbs xpt_done(ccb); 119239219Sgibbs break; 119339219Sgibbs } 119439219Sgibbs#if 0 119539219Sgibbs /* Need these??? */ 119639219Sgibbs case XPT_IMMED_NOTIFY: /* Notify Host Target driver of event */ 119739219Sgibbs case XPT_NOTIFY_ACK: /* Acknowledgement of event */ 119839219Sgibbs#endif 119939219Sgibbs default: 120039219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 120139219Sgibbs xpt_done(ccb); 120239219Sgibbs break; 120339219Sgibbs } 120439219Sgibbs} 120539219Sgibbs 120639219Sgibbsstatic void 120739219Sgibbsahbpoll(struct cam_sim *sim) 120839219Sgibbs{ 120940132Sgibbs ahbintr(cam_sim_softc(sim)); 121039219Sgibbs} 121139219Sgibbs 121245577Seivindstatic void 121339219Sgibbsahbtimeout(void *arg) 121439219Sgibbs{ 121539219Sgibbs struct ecb *ecb; 121639219Sgibbs union ccb *ccb; 121739219Sgibbs struct ahb_softc *ahb; 121839219Sgibbs 121939219Sgibbs ecb = (struct ecb *)arg; 122039219Sgibbs ccb = ecb->ccb; 122139219Sgibbs ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr; 1222241590Sjhb mtx_assert(&ahb->lock, MA_OWNED); 122339219Sgibbs xpt_print_path(ccb->ccb_h.path); 122439390Sgibbs printf("ECB %p - timed out\n", (void *)ecb); 122539219Sgibbs 122639219Sgibbs if ((ecb->state & ECB_ACTIVE) == 0) { 122739219Sgibbs xpt_print_path(ccb->ccb_h.path); 122839390Sgibbs printf("ECB %p - timed out ECB already completed\n", 122939390Sgibbs (void *)ecb); 123039219Sgibbs return; 123139219Sgibbs } 123239219Sgibbs /* 123339219Sgibbs * In order to simplify the recovery process, we ask the XPT 123439219Sgibbs * layer to halt the queue of new transactions and we traverse 123539219Sgibbs * the list of pending CCBs and remove their timeouts. This 123639219Sgibbs * means that the driver attempts to clear only one error 123739219Sgibbs * condition at a time. In general, timeouts that occur 123839219Sgibbs * close together are related anyway, so there is no benefit 123939219Sgibbs * in attempting to handle errors in parrallel. Timeouts will 124039219Sgibbs * be reinstated when the recovery process ends. 124139219Sgibbs */ 124239219Sgibbs if ((ecb->state & ECB_DEVICE_RESET) == 0) { 124339219Sgibbs struct ccb_hdr *ccb_h; 124439219Sgibbs 124539219Sgibbs if ((ecb->state & ECB_RELEASE_SIMQ) == 0) { 124639219Sgibbs xpt_freeze_simq(ahb->sim, /*count*/1); 124739219Sgibbs ecb->state |= ECB_RELEASE_SIMQ; 124839219Sgibbs } 124939219Sgibbs 1250241590Sjhb LIST_FOREACH(ccb_h, &ahb->pending_ccbs, sim_links.le) { 125139219Sgibbs struct ecb *pending_ecb; 125239219Sgibbs 125339219Sgibbs pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr; 1254241590Sjhb callout_stop(&pending_ecb->timer); 125539219Sgibbs } 125639219Sgibbs 125739219Sgibbs /* Store for our interrupt handler */ 125839219Sgibbs ahb->immed_ecb = ecb; 125939219Sgibbs 126039219Sgibbs /* 126139219Sgibbs * Send a Bus Device Reset message: 126239219Sgibbs * The target that is holding up the bus may not 126339219Sgibbs * be the same as the one that triggered this timeout 126439219Sgibbs * (different commands have different timeout lengths), 126539219Sgibbs * but we have no way of determining this from our 126639219Sgibbs * timeout handler. Our strategy here is to queue a 126739219Sgibbs * BDR message to the target of the timed out command. 126839219Sgibbs * If this fails, we'll get another timeout 2 seconds 126939219Sgibbs * later which will attempt a bus reset. 127039219Sgibbs */ 127139219Sgibbs xpt_print_path(ccb->ccb_h.path); 127239324Sgibbs printf("Queuing BDR\n"); 127339219Sgibbs ecb->state |= ECB_DEVICE_RESET; 1274241590Sjhb callout_reset(&ecb->timer, 2 * hz, ahbtimeout, ecb); 127539219Sgibbs 127639219Sgibbs ahb->immed_cmd = IMMED_RESET; 127739219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id); 127839219Sgibbs } else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) { 127939219Sgibbs /* 128039219Sgibbs * Try a SCSI bus reset. We do this only if we 128139219Sgibbs * have already attempted to clear the condition with a BDR. 128239219Sgibbs */ 128339219Sgibbs xpt_print_path(ccb->ccb_h.path); 128439324Sgibbs printf("Attempting SCSI Bus reset\n"); 128539219Sgibbs ecb->state |= ECB_SCSIBUS_RESET; 1286241590Sjhb callout_reset(&ecb->timer, 2 * hz, ahbtimeout, ecb); 128739219Sgibbs ahb->immed_cmd = IMMED_RESET; 128839219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id); 128939219Sgibbs } else { 129039219Sgibbs /* Bring out the hammer... */ 129139219Sgibbs ahbreset(ahb); 129239219Sgibbs 129339219Sgibbs /* Simulate the reset complete interrupt */ 129439219Sgibbs ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK); 129539219Sgibbs } 129639219Sgibbs} 129739219Sgibbs 129845791Speterstatic device_method_t ahb_eisa_methods[] = { 129945791Speter /* Device interface */ 130045791Speter DEVMETHOD(device_probe, ahbprobe), 130145791Speter DEVMETHOD(device_attach, ahbattach), 130245791Speter 130345791Speter { 0, 0 } 130445791Speter}; 130545791Speter 130645791Speterstatic driver_t ahb_eisa_driver = { 130745791Speter "ahb", 130845791Speter ahb_eisa_methods, 1309241590Sjhb sizeof(struct ahb_softc), 131045791Speter}; 131145791Speter 131245791Speterstatic devclass_t ahb_devclass; 131345791Speter 131445791SpeterDRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0); 1315165102SmjacobMODULE_DEPEND(ahb, eisa, 1, 1, 1); 1316165102SmjacobMODULE_DEPEND(ahb, cam, 1, 1, 1); 1317