ahb.c revision 115343
139219Sgibbs/* 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: head/sys/dev/ahb/ahb.c 115343 2003-05-27 04:59:59Z scottl $ 2939219Sgibbs */ 3039219Sgibbs 3139219Sgibbs#include <sys/param.h> 3239219Sgibbs#include <sys/systm.h> 3339219Sgibbs#include <sys/kernel.h> 3439219Sgibbs#include <sys/malloc.h> 3545791Speter#include <sys/module.h> 3645791Speter#include <sys/bus.h> 3739219Sgibbs 3839219Sgibbs#include <machine/bus_pio.h> 3939219Sgibbs#include <machine/bus.h> 4045791Speter#include <machine/resource.h> 4145791Speter#include <sys/rman.h> 4239219Sgibbs 4339219Sgibbs#include <cam/cam.h> 4439219Sgibbs#include <cam/cam_ccb.h> 4539219Sgibbs#include <cam/cam_sim.h> 4639219Sgibbs#include <cam/cam_xpt_sim.h> 4739219Sgibbs#include <cam/cam_debug.h> 4839219Sgibbs 4939219Sgibbs#include <cam/scsi/scsi_message.h> 5039219Sgibbs 5155953Speter#include <dev/eisa/eisaconf.h> 5239219Sgibbs 5355953Speter#include <dev/ahb/ahbreg.h> 5439219Sgibbs 5539219Sgibbs#define ccb_ecb_ptr spriv_ptr0 5639219Sgibbs#define ccb_ahb_ptr spriv_ptr1 5739219Sgibbs 5839219Sgibbs#define ahb_inb(ahb, port) \ 5939219Sgibbs bus_space_read_1((ahb)->tag, (ahb)->bsh, port) 6039219Sgibbs 6139219Sgibbs#define ahb_inl(ahb, port) \ 6239219Sgibbs bus_space_read_4((ahb)->tag, (ahb)->bsh, port) 6339219Sgibbs 6439219Sgibbs#define ahb_outb(ahb, port, value) \ 6539219Sgibbs bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value) 6639219Sgibbs 6739219Sgibbs#define ahb_outl(ahb, port, value) \ 6839219Sgibbs bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value) 6939219Sgibbs 7039219Sgibbsstatic const char *ahbmatch(eisa_id_t type); 7156177Snyanstatic struct ahb_softc *ahballoc(u_long unit, struct resource *res); 7239219Sgibbsstatic void ahbfree(struct ahb_softc *ahb); 7339219Sgibbsstatic int ahbreset(struct ahb_softc *ahb); 7439219Sgibbsstatic void ahbmapecbs(void *arg, bus_dma_segment_t *segs, 7539219Sgibbs int nseg, int error); 7639219Sgibbsstatic int ahbxptattach(struct ahb_softc *ahb); 7739219Sgibbsstatic void ahbhandleimmed(struct ahb_softc *ahb, 7839219Sgibbs u_int32_t mbox, u_int intstat); 7939219Sgibbsstatic void ahbcalcresid(struct ahb_softc *ahb, 8039219Sgibbs struct ecb *ecb, union ccb *ccb); 8139219Sgibbsstatic __inline void ahbdone(struct ahb_softc *ahb, u_int32_t mbox, 8239219Sgibbs u_int intstat); 8339219Sgibbsstatic void ahbintr(void *arg); 8439219Sgibbsstatic bus_dmamap_callback_t ahbexecuteecb; 8539219Sgibbsstatic void ahbaction(struct cam_sim *sim, union ccb *ccb); 8639219Sgibbsstatic void ahbpoll(struct cam_sim *sim); 8739219Sgibbs 8839219Sgibbs/* Our timeout handler */ 8945967Sgibbsstatic timeout_t ahbtimeout; 9039219Sgibbs 9139219Sgibbsstatic __inline struct ecb* ahbecbget(struct ahb_softc *ahb); 9239219Sgibbsstatic __inline void ahbecbfree(struct ahb_softc* ahb, 9339219Sgibbs struct ecb* ecb); 9439219Sgibbsstatic __inline u_int32_t ahbecbvtop(struct ahb_softc *ahb, 9539219Sgibbs struct ecb *ecb); 9639219Sgibbsstatic __inline struct ecb* ahbecbptov(struct ahb_softc *ahb, 9739219Sgibbs u_int32_t ecb_addr); 9839219Sgibbsstatic __inline u_int32_t ahbstatuspaddr(u_int32_t ecb_paddr); 9939219Sgibbsstatic __inline u_int32_t ahbsensepaddr(u_int32_t ecb_paddr); 10039219Sgibbsstatic __inline u_int32_t ahbsgpaddr(u_int32_t ecb_paddr); 10139219Sgibbsstatic __inline void ahbqueuembox(struct ahb_softc *ahb, 10239219Sgibbs u_int32_t mboxval, 10339219Sgibbs u_int attn_code); 10439219Sgibbs 10539219Sgibbsstatic __inline struct ecb* 10639219Sgibbsahbecbget(struct ahb_softc *ahb) 10739219Sgibbs{ 10839219Sgibbs struct ecb* ecb; 10939219Sgibbs int s; 11039219Sgibbs 11139219Sgibbs s = splcam(); 11239219Sgibbs if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL) 11339219Sgibbs SLIST_REMOVE_HEAD(&ahb->free_ecbs, links); 11439219Sgibbs splx(s); 11539219Sgibbs 11639219Sgibbs return (ecb); 11739219Sgibbs} 11839219Sgibbs 11939219Sgibbsstatic __inline void 12039219Sgibbsahbecbfree(struct ahb_softc* ahb, struct ecb* ecb) 12139219Sgibbs{ 12239219Sgibbs int s; 12339219Sgibbs 12439219Sgibbs s = splcam(); 12539219Sgibbs ecb->state = ECB_FREE; 12639219Sgibbs SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links); 12739219Sgibbs splx(s); 12839219Sgibbs} 12939219Sgibbs 13039219Sgibbsstatic __inline u_int32_t 13139219Sgibbsahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb) 13239219Sgibbs{ 13339219Sgibbs return (ahb->ecb_physbase 13439219Sgibbs + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array)); 13539219Sgibbs} 13639219Sgibbs 13739219Sgibbsstatic __inline struct ecb* 13839219Sgibbsahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr) 13939219Sgibbs{ 14039219Sgibbs return (ahb->ecb_array 14139219Sgibbs + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase)); 14239219Sgibbs} 14339219Sgibbs 14439219Sgibbsstatic __inline u_int32_t 14539219Sgibbsahbstatuspaddr(u_int32_t ecb_paddr) 14639219Sgibbs{ 14739219Sgibbs return (ecb_paddr + offsetof(struct ecb, status)); 14839219Sgibbs} 14939219Sgibbs 15039219Sgibbsstatic __inline u_int32_t 15139219Sgibbsahbsensepaddr(u_int32_t ecb_paddr) 15239219Sgibbs{ 15339219Sgibbs return (ecb_paddr + offsetof(struct ecb, sense)); 15439219Sgibbs} 15539219Sgibbs 15639219Sgibbsstatic __inline u_int32_t 15739219Sgibbsahbsgpaddr(u_int32_t ecb_paddr) 15839219Sgibbs{ 15939219Sgibbs return (ecb_paddr + offsetof(struct ecb, sg_list)); 16039219Sgibbs} 16139219Sgibbs 16239219Sgibbsstatic __inline void 16339219Sgibbsahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code) 16439219Sgibbs{ 16539219Sgibbs u_int loopmax = 300; 16639219Sgibbs while (--loopmax) { 16739219Sgibbs u_int status; 16839219Sgibbs 16939219Sgibbs status = ahb_inb(ahb, HOSTSTAT); 17043312Sdillon if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY)) 17143316Sgibbs == HOSTSTAT_MBOX_EMPTY) 17239219Sgibbs break; 17339219Sgibbs DELAY(20); 17439219Sgibbs } 17539219Sgibbs if (loopmax == 0) 17639324Sgibbs panic("ahb%ld: adapter not taking commands\n", ahb->unit); 17739219Sgibbs 17839219Sgibbs ahb_outl(ahb, MBOXOUT0, mboxval); 17939219Sgibbs ahb_outb(ahb, ATTN, attn_code); 18039219Sgibbs} 18139219Sgibbs 18239219Sgibbsstatic const char * 18339219Sgibbsahbmatch(eisa_id_t type) 18439219Sgibbs{ 18539219Sgibbs switch(type & 0xfffffe00) { 18639219Sgibbs case EISA_DEVICE_ID_ADAPTEC_1740: 18739219Sgibbs return ("Adaptec 174x SCSI host adapter"); 18839219Sgibbs break; 18939219Sgibbs default: 19039219Sgibbs break; 19139219Sgibbs } 19239219Sgibbs return (NULL); 19339219Sgibbs} 19439219Sgibbs 19539219Sgibbsstatic int 19645791Speterahbprobe(device_t dev) 19739219Sgibbs{ 19845791Speter const char *desc; 19939219Sgibbs u_int32_t iobase; 20039219Sgibbs u_int32_t irq; 20145791Speter u_int8_t intdef; 20249360Smdodd int shared; 20339219Sgibbs 20445791Speter desc = ahbmatch(eisa_get_id(dev)); 20545791Speter if (!desc) 20645791Speter return (ENXIO); 20745791Speter device_set_desc(dev, desc); 20839219Sgibbs 20945791Speter iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + 21045791Speter AHB_EISA_SLOT_OFFSET; 21139219Sgibbs 21245791Speter eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE); 21339219Sgibbs 21445791Speter intdef = inb(INTDEF + iobase); 21545791Speter switch (intdef & 0x7) { 21645791Speter case INT9: 21745791Speter irq = 9; 21845791Speter break; 21945791Speter case INT10: 22045791Speter irq = 10; 22145791Speter break; 22245791Speter case INT11: 22345791Speter irq = 11; 22445791Speter break; 22545791Speter case INT12: 22645791Speter irq = 12; 22745791Speter break; 22845791Speter case INT14: 22945791Speter irq = 14; 23045791Speter break; 23145791Speter case INT15: 23245791Speter irq = 15; 23345791Speter break; 23445791Speter default: 23545791Speter printf("Adaptec 174X at slot %d: illegal " 23645791Speter "irq setting %d\n", eisa_get_slot(dev), 23745791Speter (intdef & 0x7)); 23845791Speter irq = 0; 23945791Speter break; 24039219Sgibbs } 24145791Speter if (irq == 0) 24245791Speter return ENXIO; 24345791Speter 24449360Smdodd shared = (inb(INTDEF + iobase) & INTLEVEL) ? 24549360Smdodd EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE; 24645791Speter 24749360Smdodd eisa_add_intr(dev, irq, shared); 24849360Smdodd 24945791Speter return 0; 25039219Sgibbs} 25139219Sgibbs 25239219Sgibbsstatic int 25345791Speterahbattach(device_t dev) 25439219Sgibbs{ 25539219Sgibbs /* 25639219Sgibbs * find unit and check we have that many defined 25739219Sgibbs */ 25839219Sgibbs struct ahb_softc *ahb; 25939219Sgibbs struct ecb* next_ecb; 26045791Speter struct resource *io = 0; 26145791Speter struct resource *irq = 0; 26249360Smdodd int rid; 26345791Speter void *ih; 26439219Sgibbs 26545791Speter rid = 0; 26645791Speter io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 26745791Speter 0, ~0, 1, RF_ACTIVE); 26845791Speter if (!io) { 26945791Speter device_printf(dev, "No I/O space?!\n"); 27045791Speter return ENOMEM; 27139219Sgibbs } 27239219Sgibbs 27356177Snyan if ((ahb = ahballoc(device_get_unit(dev), io)) == NULL) { 27445791Speter goto error_exit2; 27539219Sgibbs } 27639219Sgibbs 27739219Sgibbs if (ahbreset(ahb) != 0) 27845791Speter goto error_exit; 27939219Sgibbs 28045791Speter rid = 0; 28145791Speter irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 28249360Smdodd 0, ~0, 1, RF_ACTIVE); 28345791Speter if (!irq) { 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. */ 29439219Sgibbs /* XXX Should be a child of the EISA bus dma tag */ 295112782Smdodd if (bus_dma_tag_create( /* parent */ NULL, 296112782Smdodd /* alignment */ 1, 297112782Smdodd /* boundary */ 0, 298112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 299112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 300112782Smdodd /* filter */ NULL, 301112782Smdodd /* filterarg */ NULL, 302112782Smdodd /* maxsize */ MAXBSIZE, 303112782Smdodd /* nsegments */ AHB_NSEG, 304112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 305112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 306112782Smdodd &ahb->buffer_dmat) != 0) 30739219Sgibbs goto error_exit; 30839219Sgibbs 30939219Sgibbs ahb->init_level++; 31039219Sgibbs 31139219Sgibbs /* DMA tag for our ccb structures and ha inquiry data */ 312112782Smdodd if (bus_dma_tag_create( /* parent */ NULL, 313112782Smdodd /* alignment */ 1, 314112782Smdodd /* boundary */ 0, 315112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 316112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 317112782Smdodd /* filter */ NULL, 318112782Smdodd /* filterarg */ NULL, 319112782Smdodd /* maxsize */ (AHB_NECB * 320112782Smdodd sizeof(struct ecb)) 321112782Smdodd + sizeof(*ahb->ha_inq_data), 322112782Smdodd /* nsegments */ 1, 323112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 324112782Smdodd /* flags */ 0, 325112782Smdodd &ahb->ecb_dmat) != 0) 32639219Sgibbs goto error_exit; 32739219Sgibbs 32839219Sgibbs ahb->init_level++; 32939219Sgibbs 33039219Sgibbs /* Allocation for our ccbs */ 33139219Sgibbs if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array, 33239219Sgibbs BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0) 33339219Sgibbs goto error_exit; 33439219Sgibbs 33539219Sgibbs ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB]; 33639219Sgibbs 33739219Sgibbs ahb->init_level++; 33839219Sgibbs 33939219Sgibbs /* And permanently map them */ 34039219Sgibbs bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap, 34139219Sgibbs ahb->ecb_array, AHB_NSEG * sizeof(struct ecb), 34239219Sgibbs ahbmapecbs, ahb, /*flags*/0); 34339219Sgibbs 34439219Sgibbs ahb->init_level++; 34539219Sgibbs 34639219Sgibbs /* Allocate the buffer dmamaps for each of our ECBs */ 34739219Sgibbs bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb)) 34839219Sgibbs + sizeof(*ahb->ha_inq_data)); 34939219Sgibbs next_ecb = ahb->ecb_array; 35039219Sgibbs while (ahb->num_ecbs < AHB_NECB) { 35139219Sgibbs u_int32_t ecb_paddr; 35239219Sgibbs 35339219Sgibbs if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0, 35439219Sgibbs &next_ecb->dmamap)) 35539219Sgibbs break; 35639219Sgibbs ecb_paddr = ahbecbvtop(ahb, next_ecb); 35739219Sgibbs next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr); 35839219Sgibbs next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr); 35939219Sgibbs ahb->num_ecbs++; 36039219Sgibbs ahbecbfree(ahb, next_ecb); 36139219Sgibbs next_ecb++; 36239219Sgibbs } 36339219Sgibbs 36439219Sgibbs if (ahb->num_ecbs == 0) 36539219Sgibbs goto error_exit; 36639219Sgibbs 36739219Sgibbs ahb->init_level++; 36839219Sgibbs 36939219Sgibbs /* 37039219Sgibbs * Now that we know we own the resources we need, register 37139219Sgibbs * our bus with the XPT. 37239219Sgibbs */ 37339219Sgibbs if (ahbxptattach(ahb)) 37439219Sgibbs goto error_exit; 37539219Sgibbs 37639219Sgibbs /* Enable our interrupt */ 37773280Smarkm bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, ahbintr, ahb, &ih); 37839219Sgibbs return (0); 37945791Speter 38039219Sgibbserror_exit: 38139219Sgibbs /* 38239219Sgibbs * The board's IRQ line will not be left enabled 38339219Sgibbs * if we can't intialize correctly, so its safe 38439219Sgibbs * to release the irq. 38539219Sgibbs */ 38639219Sgibbs ahbfree(ahb); 38745791Spetererror_exit2: 38845791Speter if (io) 38945791Speter bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 39045791Speter if (irq) 39145791Speter bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 39239219Sgibbs return (-1); 39339219Sgibbs} 39439219Sgibbs 39539219Sgibbsstatic struct ahb_softc * 39656177Snyanahballoc(u_long unit, struct resource *res) 39739219Sgibbs{ 39839219Sgibbs struct ahb_softc *ahb; 39939219Sgibbs 40039219Sgibbs /* 40139219Sgibbs * Allocate a storage area for us 40239219Sgibbs */ 40367888Sdwmalone ahb = malloc(sizeof(struct ahb_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 40439219Sgibbs if (!ahb) { 40539324Sgibbs printf("ahb%ld: cannot malloc!\n", unit); 40639219Sgibbs return (NULL); 40739219Sgibbs } 40839219Sgibbs SLIST_INIT(&ahb->free_ecbs); 40939219Sgibbs LIST_INIT(&ahb->pending_ccbs); 41039219Sgibbs ahb->unit = unit; 41156177Snyan ahb->tag = rman_get_bustag(res); 41256177Snyan ahb->bsh = rman_get_bushandle(res); 41339219Sgibbs ahb->disc_permitted = ~0; 41439219Sgibbs ahb->tags_permitted = ~0; 41539219Sgibbs 41639219Sgibbs return (ahb); 41739219Sgibbs} 41839219Sgibbs 41939219Sgibbsstatic void 42039219Sgibbsahbfree(struct ahb_softc *ahb) 42139219Sgibbs{ 42239219Sgibbs switch (ahb->init_level) { 42339219Sgibbs default: 42439219Sgibbs case 4: 42539219Sgibbs bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap); 42639219Sgibbs case 3: 42739219Sgibbs bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array, 42839219Sgibbs ahb->ecb_dmamap); 42939219Sgibbs bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap); 43039219Sgibbs case 2: 43139219Sgibbs bus_dma_tag_destroy(ahb->ecb_dmat); 43239219Sgibbs case 1: 43339219Sgibbs bus_dma_tag_destroy(ahb->buffer_dmat); 43439219Sgibbs case 0: 43597208Speter break; 43639219Sgibbs } 43739219Sgibbs free(ahb, M_DEVBUF); 43839219Sgibbs} 43939219Sgibbs 44039219Sgibbs/* 44139219Sgibbs * reset board, If it doesn't respond, return failure 44239219Sgibbs */ 44339219Sgibbsstatic int 44439219Sgibbsahbreset(struct ahb_softc *ahb) 44539219Sgibbs{ 44639219Sgibbs int wait = 1000; /* 1 sec enough? */ 44739219Sgibbs int test; 44839219Sgibbs 44939219Sgibbs if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) { 45039219Sgibbs printf("ahb_reset: Controller not in enhanced mode\n"); 45139219Sgibbs return (-1); 45239219Sgibbs } 45339219Sgibbs 45439219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_HARD_RST); 45539219Sgibbs DELAY(1000); 45639219Sgibbs ahb_outb(ahb, CONTROL, 0); 45739219Sgibbs while (--wait) { 45839219Sgibbs DELAY(1000); 45939219Sgibbs if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0) 46039219Sgibbs break; 46139219Sgibbs } 46239219Sgibbs 46339219Sgibbs if (wait == 0) { 46439219Sgibbs printf("ahbreset: No answer from aha1742 board\n"); 46539219Sgibbs return (-1); 46639219Sgibbs } 46739219Sgibbs if ((test = ahb_inb(ahb, MBOXIN0)) != 0) { 46839219Sgibbs printf("ahb_reset: self test failed, val = 0x%x\n", test); 46939219Sgibbs return (-1); 47039219Sgibbs } 47139219Sgibbs while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) { 47239219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_CLRINT); 47339219Sgibbs DELAY(10000); 47439219Sgibbs } 47539219Sgibbs return (0); 47639219Sgibbs} 47739219Sgibbs 47839219Sgibbsstatic void 47939219Sgibbsahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 48039219Sgibbs{ 48139219Sgibbs struct ahb_softc* ahb; 48239219Sgibbs 48339219Sgibbs ahb = (struct ahb_softc*)arg; 48439219Sgibbs ahb->ecb_physbase = segs->ds_addr; 48539219Sgibbs /* 48639219Sgibbs * Space for adapter inquiry information is on the 48739219Sgibbs * tail of the ecb array. 48839219Sgibbs */ 48939219Sgibbs ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]); 49039219Sgibbs} 49139219Sgibbs 49239219Sgibbsstatic int 49339219Sgibbsahbxptattach(struct ahb_softc *ahb) 49439219Sgibbs{ 49539219Sgibbs struct cam_devq *devq; 49639219Sgibbs struct ecb *ecb; 49739219Sgibbs u_int i; 49839219Sgibbs 49939219Sgibbs /* Remeber who are we on the scsi bus */ 50039219Sgibbs ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID; 50139219Sgibbs 50239219Sgibbs /* Use extended translation?? */ 50339219Sgibbs ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS; 50439219Sgibbs 50539219Sgibbs /* Fetch adapter inquiry data */ 50639219Sgibbs ecb = ahbecbget(ahb); /* Always succeeds - no outstanding commands */ 50739219Sgibbs ecb->hecb.opcode = ECBOP_READ_HA_INQDATA; 50839219Sgibbs ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY; 50939219Sgibbs ecb->hecb.data_ptr = ahb->ha_inq_physbase; 51039219Sgibbs ecb->hecb.data_len = sizeof(struct ha_inquiry_data); 51139219Sgibbs ecb->hecb.sense_ptr = 0; 51239219Sgibbs ecb->state = ECB_ACTIVE; 51339219Sgibbs 51439219Sgibbs /* Tell the adapter about this command */ 51539219Sgibbs ahbqueuembox(ahb, ahbecbvtop(ahb, ecb), 51639219Sgibbs ATTN_STARTECB|ahb->scsi_id); 51739219Sgibbs 51839219Sgibbs /* Poll for interrupt completion */ 51939219Sgibbs for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) { 52039219Sgibbs ahbintr(ahb); 52139219Sgibbs DELAY(1000); 52239219Sgibbs } 52339219Sgibbs 52439219Sgibbs ahb->num_ecbs = MIN(ahb->num_ecbs, 52539219Sgibbs ahb->ha_inq_data->scsi_data.reserved[1]); 52639324Sgibbs printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n", 52739219Sgibbs ahb->unit, ahb->ha_inq_data->scsi_data.product, 52839219Sgibbs (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential" 52939219Sgibbs : "Single Ended", 53039219Sgibbs ahb->ha_inq_data->scsi_data.revision, 53139219Sgibbs ahb->scsi_id, ahb->num_ecbs); 53239219Sgibbs 53339219Sgibbs /* Restore sense paddr for future CCB clients */ 53439219Sgibbs ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb)); 53539219Sgibbs 53639219Sgibbs ahbecbfree(ahb, ecb); 53739219Sgibbs 53839219Sgibbs /* 53939219Sgibbs * Create the device queue for our SIM. 54039219Sgibbs */ 54139219Sgibbs devq = cam_simq_alloc(ahb->num_ecbs); 54239219Sgibbs if (devq == NULL) 54339219Sgibbs return (ENOMEM); 54439219Sgibbs 54539219Sgibbs /* 54639219Sgibbs * Construct our SIM entry 54739219Sgibbs */ 54839219Sgibbs ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit, 54939219Sgibbs 2, ahb->num_ecbs, devq); 55039219Sgibbs if (ahb->sim == NULL) { 55139219Sgibbs cam_simq_free(devq); 55239219Sgibbs return (ENOMEM); 55339219Sgibbs } 55439219Sgibbs 55539219Sgibbs if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) { 55639219Sgibbs cam_sim_free(ahb->sim, /*free_devq*/TRUE); 55739219Sgibbs return (ENXIO); 55839219Sgibbs } 55939219Sgibbs 56039219Sgibbs if (xpt_create_path(&ahb->path, /*periph*/NULL, 56139219Sgibbs cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD, 56239219Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 56339219Sgibbs xpt_bus_deregister(cam_sim_path(ahb->sim)); 56439219Sgibbs cam_sim_free(ahb->sim, /*free_devq*/TRUE); 56539219Sgibbs return (ENXIO); 56639219Sgibbs } 56739219Sgibbs 56839219Sgibbs /* 56939219Sgibbs * Allow the board to generate interrupts. 57039219Sgibbs */ 57139219Sgibbs ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN); 57239219Sgibbs 57339219Sgibbs return (0); 57439219Sgibbs} 57539219Sgibbs 57639219Sgibbsstatic void 57739219Sgibbsahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat) 57839219Sgibbs{ 57939219Sgibbs struct ccb_hdr *ccb_h; 58039219Sgibbs u_int target_id; 58139219Sgibbs 58239219Sgibbs if (ahb->immed_cmd == 0) { 58339324Sgibbs printf("ahb%ld: Immediate Command complete with no " 58439324Sgibbs " pending command\n", ahb->unit); 58539219Sgibbs return; 58639219Sgibbs } 58739219Sgibbs 58839219Sgibbs target_id = intstat & INTSTAT_TARGET_MASK; 58939219Sgibbs 59039219Sgibbs ccb_h = LIST_FIRST(&ahb->pending_ccbs); 59139219Sgibbs while (ccb_h != NULL) { 59239219Sgibbs struct ecb *pending_ecb; 59339219Sgibbs union ccb *ccb; 59439219Sgibbs 59539219Sgibbs pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr; 59639219Sgibbs ccb = pending_ecb->ccb; 59739219Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 59839219Sgibbs if (ccb->ccb_h.target_id == target_id 59939219Sgibbs || target_id == ahb->scsi_id) { 60039219Sgibbs untimeout(ahbtimeout, pending_ecb, 60139219Sgibbs ccb->ccb_h.timeout_ch); 60239219Sgibbs LIST_REMOVE(&ccb->ccb_h, sim_links.le); 60339219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) 60439219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, 60539219Sgibbs pending_ecb->dmamap); 60639219Sgibbs if (pending_ecb == ahb->immed_ecb) 60739219Sgibbs ccb->ccb_h.status = 60839219Sgibbs CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ; 60939219Sgibbs else if (target_id == ahb->scsi_id) 61039219Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 61139219Sgibbs else 61239219Sgibbs ccb->ccb_h.status = CAM_BDR_SENT; 61339219Sgibbs ahbecbfree(ahb, pending_ecb); 61439219Sgibbs xpt_done(ccb); 61539219Sgibbs } else if (ahb->immed_ecb != NULL) { 61639219Sgibbs /* Re-instate timeout */ 61739219Sgibbs ccb->ccb_h.timeout_ch = 61839219Sgibbs timeout(ahbtimeout, (caddr_t)pending_ecb, 61939219Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 62039219Sgibbs } 62139219Sgibbs } 62239219Sgibbs 62339219Sgibbs if (ahb->immed_ecb != NULL) { 62439219Sgibbs ahb->immed_ecb = NULL; 62539324Sgibbs printf("ahb%ld: No longer in timeout\n", ahb->unit); 62639219Sgibbs } else if (target_id == ahb->scsi_id) 62739324Sgibbs printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit); 62839219Sgibbs else 62939324Sgibbs printf("ahb%ld: Bus Device Reset Delibered to target %d\n", 63039219Sgibbs ahb->unit, target_id); 63139219Sgibbs 63239219Sgibbs ahb->immed_cmd = 0; 63339219Sgibbs} 63439219Sgibbs 63539219Sgibbsstatic void 63639219Sgibbsahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb) 63739219Sgibbs{ 63839219Sgibbs if (ecb->status.data_overrun != 0) { 63939219Sgibbs /* 64039219Sgibbs * Overrun Condition. The hardware doesn't 64139219Sgibbs * provide a meaningful byte count in this case 64239219Sgibbs * (the residual is always 0). Tell the XPT 64339219Sgibbs * layer about the error. 64439219Sgibbs */ 64539219Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 64639219Sgibbs } else { 64739219Sgibbs ccb->csio.resid = ecb->status.resid_count; 64839219Sgibbs 64939219Sgibbs if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) { 65039219Sgibbs /* 65139219Sgibbs * For S/G transfers, the adapter provides a pointer 65239219Sgibbs * to the address in the last S/G element used and a 65339219Sgibbs * residual for that element. So, we need to sum up 65439219Sgibbs * the elements that follow it in order to get a real 65539219Sgibbs * residual number. If we have an overrun, the residual 65639219Sgibbs * reported will be 0 and we already know that all S/G 65739219Sgibbs * segments have been exhausted, so we can skip this 65839219Sgibbs * step. 65939219Sgibbs */ 66039219Sgibbs ahb_sg_t *sg; 66139219Sgibbs int num_sg; 66239219Sgibbs 66339219Sgibbs num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t); 66439219Sgibbs 66539219Sgibbs /* Find the S/G the adapter was working on */ 66639219Sgibbs for (sg = ecb->sg_list; 66739219Sgibbs num_sg != 0 && sg->addr != ecb->status.resid_addr; 66839219Sgibbs num_sg--, sg++) 66939219Sgibbs ; 67039219Sgibbs 67139219Sgibbs /* Skip it */ 67239219Sgibbs num_sg--; 67339219Sgibbs sg++; 67439219Sgibbs 67539219Sgibbs /* Sum the rest */ 67639219Sgibbs for (; num_sg != 0; num_sg--, sg++) 67739219Sgibbs ccb->csio.resid += sg->len; 67839219Sgibbs } 67939219Sgibbs /* Underruns are not errors */ 68039219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 68139219Sgibbs } 68239219Sgibbs} 68339219Sgibbs 68439219Sgibbsstatic void 68539219Sgibbsahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb) 68639219Sgibbs{ 68739219Sgibbs struct hardware_ecb *hecb; 68839219Sgibbs struct ecb_status *status; 68939219Sgibbs 69039219Sgibbs hecb = &ecb->hecb; 69139219Sgibbs status = &ecb->status; 69239219Sgibbs switch (status->ha_status) { 69339219Sgibbs case HS_OK: 69439219Sgibbs ccb->csio.scsi_status = status->scsi_status; 69539219Sgibbs if (status->scsi_status != 0) { 69639219Sgibbs ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 69739219Sgibbs if (status->sense_stored) { 69839219Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 69939219Sgibbs ccb->csio.sense_resid = 70039219Sgibbs ccb->csio.sense_len - status->sense_len; 70139219Sgibbs bcopy(&ecb->sense, &ccb->csio.sense_data, 70239219Sgibbs status->sense_len); 70339219Sgibbs } 70439219Sgibbs } 70539219Sgibbs break; 70639219Sgibbs case HS_TARGET_NOT_ASSIGNED: 70739219Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 70839219Sgibbs break; 70939219Sgibbs case HS_SEL_TIMEOUT: 71039219Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 71139219Sgibbs break; 71239219Sgibbs case HS_DATA_RUN_ERR: 71339219Sgibbs ahbcalcresid(ahb, ecb, ccb); 71439219Sgibbs break; 71539219Sgibbs case HS_UNEXPECTED_BUSFREE: 71639219Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 71739219Sgibbs break; 71839219Sgibbs case HS_INVALID_PHASE: 71939219Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 72039219Sgibbs break; 72139219Sgibbs case HS_REQUEST_SENSE_FAILED: 72239219Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 72339219Sgibbs break; 72439219Sgibbs case HS_TAG_MSG_REJECTED: 72539219Sgibbs { 72639219Sgibbs struct ccb_trans_settings neg; 72739219Sgibbs 72839219Sgibbs xpt_print_path(ccb->ccb_h.path); 72939219Sgibbs printf("refuses tagged commands. Performing " 73039219Sgibbs "non-tagged I/O\n"); 73139219Sgibbs neg.flags = 0; 73239219Sgibbs neg.valid = CCB_TRANS_TQ_VALID; 73339219Sgibbs xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 73439219Sgibbs xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg); 73539219Sgibbs ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id); 73639219Sgibbs ccb->ccb_h.status = CAM_MSG_REJECT_REC; 73739219Sgibbs break; 73839219Sgibbs } 73939219Sgibbs case HS_FIRMWARE_LOAD_REQ: 74039219Sgibbs case HS_HARDWARE_ERR: 74139219Sgibbs /* 74239219Sgibbs * Tell the system that the Adapter 74339219Sgibbs * is no longer functional. 74439219Sgibbs */ 74539219Sgibbs ccb->ccb_h.status = CAM_NO_HBA; 74639219Sgibbs break; 74739219Sgibbs case HS_CMD_ABORTED_HOST: 74839219Sgibbs case HS_CMD_ABORTED_ADAPTER: 74939219Sgibbs case HS_ATN_TARGET_FAILED: 75039219Sgibbs case HS_SCSI_RESET_ADAPTER: 75139219Sgibbs case HS_SCSI_RESET_INCOMING: 75239219Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 75339219Sgibbs break; 75449360Smdodd case HS_INVALID_ECB_PARAM: 75549360Smdodd printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n", 75649360Smdodd ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2); 75749360Smdodd ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 75849360Smdodd break; 75939219Sgibbs case HS_DUP_TCB_RECEIVED: 76039219Sgibbs case HS_INVALID_OPCODE: 76139219Sgibbs case HS_INVALID_CMD_LINK: 76239219Sgibbs case HS_PROGRAM_CKSUM_ERROR: 76339324Sgibbs panic("ahb%ld: Can't happen host status %x occurred", 76439219Sgibbs ahb->unit, status->ha_status); 76539219Sgibbs break; 76639219Sgibbs } 76739219Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 76839219Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 76939219Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 77039219Sgibbs } 77139219Sgibbs} 77239219Sgibbs 77339219Sgibbsstatic void 77439219Sgibbsahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat) 77539219Sgibbs{ 77639219Sgibbs struct ecb *ecb; 77739219Sgibbs union ccb *ccb; 77839219Sgibbs 77939219Sgibbs ecb = ahbecbptov(ahb, mbox); 78039219Sgibbs 78139219Sgibbs if ((ecb->state & ECB_ACTIVE) == 0) 78239219Sgibbs panic("ecb not active"); 78339219Sgibbs 78439219Sgibbs ccb = ecb->ccb; 78539219Sgibbs 78639219Sgibbs if (ccb != NULL) { 78739219Sgibbs untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch); 78839219Sgibbs LIST_REMOVE(&ccb->ccb_h, sim_links.le); 78939219Sgibbs 79039219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 791115343Sscottl bus_dmasync_op_t op; 79239219Sgibbs 79339219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 79439219Sgibbs op = BUS_DMASYNC_POSTREAD; 79539219Sgibbs else 79639219Sgibbs op = BUS_DMASYNC_POSTWRITE; 79739219Sgibbs bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op); 79839219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap); 79939219Sgibbs } 80039219Sgibbs 80139219Sgibbs if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) { 80239219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 80339219Sgibbs ccb->csio.resid = 0; 80439219Sgibbs } else { 80539219Sgibbs ahbprocesserror(ahb, ecb, ccb); 80639219Sgibbs } 80739219Sgibbs ahbecbfree(ahb, ecb); 80839219Sgibbs xpt_done(ccb); 80939219Sgibbs } else { 81039219Sgibbs /* Non CCB Command */ 81139219Sgibbs if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) { 81239324Sgibbs printf("ahb%ld: Command 0%x Failed %x:%x:%x\n", 81339219Sgibbs ahb->unit, ecb->hecb.opcode, 81439219Sgibbs *((u_int16_t*)&ecb->status), 81539219Sgibbs ecb->status.ha_status, ecb->status.resid_count); 81639219Sgibbs } 81739219Sgibbs /* Client owns this ECB and will release it. */ 81839219Sgibbs } 81939219Sgibbs} 82039219Sgibbs 82139219Sgibbs/* 82239219Sgibbs * Catch an interrupt from the adaptor 82339219Sgibbs */ 82439219Sgibbsstatic void 82539219Sgibbsahbintr(void *arg) 82639219Sgibbs{ 82739219Sgibbs struct ahb_softc *ahb; 82839219Sgibbs u_int intstat; 82939219Sgibbs u_int32_t mbox; 83039219Sgibbs 83139219Sgibbs ahb = (struct ahb_softc *)arg; 83239219Sgibbs 83339219Sgibbs while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) { 83439219Sgibbs /* 83539219Sgibbs * Fetch information about this interrupt. 83639219Sgibbs */ 83739219Sgibbs intstat = ahb_inb(ahb, INTSTAT); 83839219Sgibbs mbox = ahb_inl(ahb, MBOXIN0); 83939219Sgibbs 84039219Sgibbs /* 84139219Sgibbs * Reset interrupt latch. 84239219Sgibbs */ 84339219Sgibbs ahb_outb(ahb, CONTROL, CNTRL_CLRINT); 84439219Sgibbs 84539219Sgibbs /* 84639219Sgibbs * Process the completed operation 84739219Sgibbs */ 84839219Sgibbs switch (intstat & INTSTAT_MASK) { 84939219Sgibbs case INTSTAT_ECB_OK: 85039219Sgibbs case INTSTAT_ECB_CMPWRETRY: 85139219Sgibbs case INTSTAT_ECB_CMPWERR: 85239219Sgibbs ahbdone(ahb, mbox, intstat); 85339219Sgibbs break; 85439219Sgibbs case INTSTAT_AEN_OCCURED: 85539219Sgibbs if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) { 85639219Sgibbs /* Bus Reset */ 85739219Sgibbs xpt_print_path(ahb->path); 85839219Sgibbs switch (mbox) { 85939219Sgibbs case HS_SCSI_RESET_ADAPTER: 86039219Sgibbs printf("Host Adapter Initiated " 86139219Sgibbs "Bus Reset occurred\n"); 86239219Sgibbs break; 86339219Sgibbs case HS_SCSI_RESET_INCOMING: 86439219Sgibbs printf("Bus Reset Initiated " 86539219Sgibbs "by another device occurred\n"); 86639219Sgibbs break; 86739219Sgibbs } 86839219Sgibbs /* Notify the XPT */ 86939219Sgibbs xpt_async(AC_BUS_RESET, ahb->path, NULL); 87039219Sgibbs break; 87139219Sgibbs } 87239219Sgibbs printf("Unsupported initiator selection AEN occured\n"); 87339219Sgibbs break; 87439219Sgibbs case INTSTAT_IMMED_OK: 87539219Sgibbs case INTSTAT_IMMED_ERR: 87639219Sgibbs ahbhandleimmed(ahb, mbox, intstat); 87739219Sgibbs break; 87839219Sgibbs case INTSTAT_HW_ERR: 87939219Sgibbs panic("Unrecoverable hardware Error Occurred\n"); 88039219Sgibbs } 88139219Sgibbs } 88239219Sgibbs} 88339219Sgibbs 88439219Sgibbsstatic void 88539219Sgibbsahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 88639219Sgibbs{ 88739219Sgibbs struct ecb *ecb; 88839219Sgibbs union ccb *ccb; 88939219Sgibbs struct ahb_softc *ahb; 89039219Sgibbs u_int32_t ecb_paddr; 89139219Sgibbs int s; 89239219Sgibbs 89339219Sgibbs ecb = (struct ecb *)arg; 89439219Sgibbs ccb = ecb->ccb; 89539219Sgibbs ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr; 89639219Sgibbs 89739219Sgibbs if (error != 0) { 89839219Sgibbs if (error != EFBIG) 89939324Sgibbs printf("ahb%ld: Unexepected error 0x%x returned from " 90039324Sgibbs "bus_dmamap_load\n", ahb->unit, error); 90139219Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 90239219Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 90339219Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 90439219Sgibbs } 90539219Sgibbs ahbecbfree(ahb, ecb); 90639219Sgibbs xpt_done(ccb); 90739219Sgibbs return; 90839219Sgibbs } 90939219Sgibbs 91039219Sgibbs ecb_paddr = ahbecbvtop(ahb, ecb); 91139219Sgibbs 91239219Sgibbs if (nseg != 0) { 91339219Sgibbs ahb_sg_t *sg; 91439219Sgibbs bus_dma_segment_t *end_seg; 915115343Sscottl bus_dmasync_op_t op; 91639219Sgibbs 91739219Sgibbs end_seg = dm_segs + nseg; 91839219Sgibbs 91939219Sgibbs /* Copy the segments into our SG list */ 92039219Sgibbs sg = ecb->sg_list; 92139219Sgibbs while (dm_segs < end_seg) { 92239219Sgibbs sg->addr = dm_segs->ds_addr; 92339219Sgibbs sg->len = dm_segs->ds_len; 92439219Sgibbs sg++; 92539219Sgibbs dm_segs++; 92639219Sgibbs } 92739219Sgibbs 92839219Sgibbs if (nseg > 1) { 92939219Sgibbs ecb->hecb.flag_word1 |= FW1_SG_ECB; 93039219Sgibbs ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr); 93139219Sgibbs ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg; 93239219Sgibbs } else { 93339219Sgibbs ecb->hecb.data_ptr = ecb->sg_list->addr; 93439219Sgibbs ecb->hecb.data_len = ecb->sg_list->len; 93539219Sgibbs } 93639219Sgibbs 93739219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 93839219Sgibbs/* ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */ 93939219Sgibbs op = BUS_DMASYNC_PREREAD; 94039219Sgibbs } else { 94139219Sgibbs op = BUS_DMASYNC_PREWRITE; 94239219Sgibbs } 94339219Sgibbs /* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */ 94439219Sgibbs 94539219Sgibbs bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op); 94639219Sgibbs 94739219Sgibbs } else { 94839219Sgibbs ecb->hecb.data_ptr = 0; 94939219Sgibbs ecb->hecb.data_len = 0; 95039219Sgibbs } 95139219Sgibbs 95239219Sgibbs s = splcam(); 95339219Sgibbs 95439219Sgibbs /* 95539219Sgibbs * Last time we need to check if this CCB needs to 95639219Sgibbs * be aborted. 95739219Sgibbs */ 95839219Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 95939219Sgibbs if (nseg != 0) 96039219Sgibbs bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap); 96139219Sgibbs ahbecbfree(ahb, ecb); 96239219Sgibbs xpt_done(ccb); 96339219Sgibbs splx(s); 96439219Sgibbs return; 96539219Sgibbs } 96639219Sgibbs 96739219Sgibbs ecb->state = ECB_ACTIVE; 96839219Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 96939219Sgibbs LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le); 97039219Sgibbs 97139219Sgibbs /* Tell the adapter about this command */ 97239219Sgibbs ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id); 97339219Sgibbs 97439219Sgibbs ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb, 97539219Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 97639219Sgibbs splx(s); 97739219Sgibbs} 97839219Sgibbs 97939219Sgibbsstatic void 98039219Sgibbsahbaction(struct cam_sim *sim, union ccb *ccb) 98139219Sgibbs{ 98239219Sgibbs struct ahb_softc *ahb; 98339219Sgibbs 98439219Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n")); 98539219Sgibbs 98639219Sgibbs ahb = (struct ahb_softc *)cam_sim_softc(sim); 98739219Sgibbs 98839219Sgibbs switch (ccb->ccb_h.func_code) { 98939219Sgibbs /* Common cases first */ 99039219Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 99139219Sgibbs { 99239219Sgibbs struct ecb *ecb; 99339219Sgibbs struct hardware_ecb *hecb; 99439219Sgibbs 99539219Sgibbs /* 99639219Sgibbs * get an ecb to use. 99739219Sgibbs */ 99839219Sgibbs if ((ecb = ahbecbget(ahb)) == NULL) { 99939219Sgibbs /* Should never occur */ 100039219Sgibbs panic("Failed to get an ecb"); 100139219Sgibbs } 100239219Sgibbs 100339219Sgibbs /* 100439219Sgibbs * So we can find the ECB when an abort is requested 100539219Sgibbs */ 100639219Sgibbs ecb->ccb = ccb; 100739219Sgibbs ccb->ccb_h.ccb_ecb_ptr = ecb; 100839219Sgibbs ccb->ccb_h.ccb_ahb_ptr = ahb; 100939219Sgibbs 101039219Sgibbs /* 101139219Sgibbs * Put all the arguments for the xfer in the ecb 101239219Sgibbs */ 101339219Sgibbs hecb = &ecb->hecb; 101439219Sgibbs hecb->opcode = ECBOP_INITIATOR_SCSI_CMD; 101539219Sgibbs hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE 101639219Sgibbs | FW1_ERR_STATUS_BLK_ONLY; 101739219Sgibbs hecb->flag_word2 = ccb->ccb_h.target_lun 101839219Sgibbs | FW2_NO_RETRY_ON_BUSY; 101939219Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 102039219Sgibbs hecb->flag_word2 |= FW2_TAG_ENB 102139219Sgibbs | ((ccb->csio.tag_action & 0x3) 102239219Sgibbs << FW2_TAG_TYPE_SHIFT); 102339219Sgibbs } 102439219Sgibbs if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) 102539219Sgibbs hecb->flag_word2 |= FW2_DISABLE_DISC; 102639219Sgibbs hecb->sense_len = ccb->csio.sense_len; 102739219Sgibbs hecb->cdb_len = ccb->csio.cdb_len; 102839219Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 102939219Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 103039219Sgibbs bcopy(ccb->csio.cdb_io.cdb_ptr, 103139219Sgibbs hecb->cdb, hecb->cdb_len); 103239219Sgibbs } else { 103339219Sgibbs /* I guess I could map it in... */ 103439219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 103539219Sgibbs ahbecbfree(ahb, ecb); 103639219Sgibbs xpt_done(ccb); 103739219Sgibbs return; 103839219Sgibbs } 103939219Sgibbs } else { 104039219Sgibbs bcopy(ccb->csio.cdb_io.cdb_bytes, 104139219Sgibbs hecb->cdb, hecb->cdb_len); 104239219Sgibbs } 104339219Sgibbs 104439219Sgibbs /* 104539219Sgibbs * If we have any data to send with this command, 104639219Sgibbs * map it into bus space. 104739219Sgibbs */ 104839219Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 104939219Sgibbs if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 105039219Sgibbs /* 105139219Sgibbs * We've been given a pointer 105239219Sgibbs * to a single buffer. 105339219Sgibbs */ 105439219Sgibbs if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) { 105539219Sgibbs int s; 105639219Sgibbs int error; 105739219Sgibbs 105839219Sgibbs s = splsoftvm(); 105939219Sgibbs error = bus_dmamap_load( 106039219Sgibbs ahb->buffer_dmat, 106139219Sgibbs ecb->dmamap, 106239219Sgibbs ccb->csio.data_ptr, 106339219Sgibbs ccb->csio.dxfer_len, 106439219Sgibbs ahbexecuteecb, 106539219Sgibbs ecb, /*flags*/0); 106639219Sgibbs if (error == EINPROGRESS) { 106739219Sgibbs /* 106839219Sgibbs * So as to maintain ordering, 106939219Sgibbs * freeze the controller queue 107039219Sgibbs * until our mapping is 107139219Sgibbs * returned. 107239219Sgibbs */ 107339219Sgibbs xpt_freeze_simq(ahb->sim, 1); 107439219Sgibbs ccb->ccb_h.status |= 107539219Sgibbs CAM_RELEASE_SIMQ; 107639219Sgibbs } 107739219Sgibbs splx(s); 107839219Sgibbs } else { 107939219Sgibbs struct bus_dma_segment seg; 108039219Sgibbs 108139219Sgibbs /* Pointer to physical buffer */ 108239219Sgibbs seg.ds_addr = 108339219Sgibbs (bus_addr_t)ccb->csio.data_ptr; 108439219Sgibbs seg.ds_len = ccb->csio.dxfer_len; 108539219Sgibbs ahbexecuteecb(ecb, &seg, 1, 0); 108639219Sgibbs } 108739219Sgibbs } else { 108839219Sgibbs struct bus_dma_segment *segs; 108939219Sgibbs 109039219Sgibbs if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0) 109139219Sgibbs panic("ahbaction - Physical segment " 109239219Sgibbs "pointers unsupported"); 109339219Sgibbs 109439219Sgibbs if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) 109539219Sgibbs panic("btaction - Virtual segment " 109639219Sgibbs "addresses unsupported"); 109739219Sgibbs 109839219Sgibbs /* Just use the segments provided */ 109939219Sgibbs segs = (struct bus_dma_segment *) 110039219Sgibbs ccb->csio.data_ptr; 110139219Sgibbs ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt, 110239219Sgibbs 0); 110339219Sgibbs } 110439219Sgibbs } else { 110539219Sgibbs ahbexecuteecb(ecb, NULL, 0, 0); 110639219Sgibbs } 110739219Sgibbs break; 110839219Sgibbs } 110939219Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 111039219Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 111139219Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 111239219Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 111339219Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 111439219Sgibbs /* XXX Implement */ 111539219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 111639219Sgibbs xpt_done(ccb); 111739219Sgibbs break; 111839219Sgibbs case XPT_SET_TRAN_SETTINGS: 111939219Sgibbs { 112039219Sgibbs ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 112139219Sgibbs xpt_done(ccb); 112239219Sgibbs break; 112339219Sgibbs } 112439219Sgibbs case XPT_GET_TRAN_SETTINGS: 112539219Sgibbs /* Get default/user set transfer settings for the target */ 112639219Sgibbs { 112739219Sgibbs struct ccb_trans_settings *cts; 112839219Sgibbs u_int target_mask; 112939219Sgibbs 113039219Sgibbs cts = &ccb->cts; 113139219Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 113239219Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 113339219Sgibbs cts->flags = 0; 113439219Sgibbs if ((ahb->disc_permitted & target_mask) != 0) 113539219Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 113639219Sgibbs if ((ahb->tags_permitted & target_mask) != 0) 113739219Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 113839219Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 113939219Sgibbs cts->sync_period = 25; /* 10MHz */ 114039219Sgibbs 114139219Sgibbs if (cts->sync_period != 0) 114239219Sgibbs cts->sync_offset = 15; 114339219Sgibbs 114439219Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 114539219Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 114639219Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 114739219Sgibbs | CCB_TRANS_DISC_VALID 114839219Sgibbs | CCB_TRANS_TQ_VALID; 114939219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 115039219Sgibbs } else { 115139219Sgibbs ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 115239219Sgibbs } 115339219Sgibbs xpt_done(ccb); 115439219Sgibbs break; 115539219Sgibbs } 115639219Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 115739219Sgibbs { 115839219Sgibbs int i; 115944508Sgibbs int s; 116039219Sgibbs 116144508Sgibbs s = splcam(); 116239219Sgibbs ahb->immed_cmd = IMMED_RESET; 116339219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id); 116439219Sgibbs /* Poll for interrupt completion */ 116544508Sgibbs for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) { 116639219Sgibbs DELAY(1000); 116744508Sgibbs ahbintr(cam_sim_softc(sim)); 116844508Sgibbs } 116944508Sgibbs splx(s); 117039219Sgibbs break; 117139219Sgibbs } 117239219Sgibbs case XPT_CALC_GEOMETRY: 117339219Sgibbs { 117439219Sgibbs struct ccb_calc_geometry *ccg; 117539219Sgibbs u_int32_t size_mb; 117639219Sgibbs u_int32_t secs_per_cylinder; 117739219Sgibbs 117839219Sgibbs ccg = &ccb->ccg; 117939219Sgibbs size_mb = ccg->volume_size 118039219Sgibbs / ((1024L * 1024L) / ccg->block_size); 118139219Sgibbs 118239219Sgibbs if (size_mb > 1024 && (ahb->extended_trans != 0)) { 118339219Sgibbs ccg->heads = 255; 118439219Sgibbs ccg->secs_per_track = 63; 118539219Sgibbs } else { 118639219Sgibbs ccg->heads = 64; 118739219Sgibbs ccg->secs_per_track = 32; 118839219Sgibbs } 118939219Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 119039219Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 119139219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 119239219Sgibbs xpt_done(ccb); 119339219Sgibbs break; 119439219Sgibbs } 119539219Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 119639219Sgibbs { 119739219Sgibbs int i; 119839219Sgibbs 119939219Sgibbs ahb->immed_cmd = IMMED_RESET; 120039219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id); 120139219Sgibbs /* Poll for interrupt completion */ 120239219Sgibbs for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) 120339219Sgibbs DELAY(1000); 120439219Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 120539219Sgibbs xpt_done(ccb); 120639219Sgibbs break; 120739219Sgibbs } 120839219Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 120939219Sgibbs /* XXX Implement */ 121039219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 121139219Sgibbs xpt_done(ccb); 121239219Sgibbs break; 121339219Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 121439219Sgibbs { 121539219Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 121639219Sgibbs 121739219Sgibbs cpi->version_num = 1; /* XXX??? */ 121839219Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 121939219Sgibbs cpi->target_sprt = 0; 122039219Sgibbs cpi->hba_misc = 0; 122139219Sgibbs cpi->hba_eng_cnt = 0; 122239219Sgibbs cpi->max_target = 7; 122339219Sgibbs cpi->max_lun = 7; 122439219Sgibbs cpi->initiator_id = ahb->scsi_id; 122539219Sgibbs cpi->bus_id = cam_sim_bus(sim); 122646581Sken cpi->base_transfer_speed = 3300; 122739219Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 122839219Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 122939219Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 123039219Sgibbs cpi->unit_number = cam_sim_unit(sim); 123139219Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 123239219Sgibbs xpt_done(ccb); 123339219Sgibbs break; 123439219Sgibbs } 123539219Sgibbs#if 0 123639219Sgibbs /* Need these??? */ 123739219Sgibbs case XPT_IMMED_NOTIFY: /* Notify Host Target driver of event */ 123839219Sgibbs case XPT_NOTIFY_ACK: /* Acknowledgement of event */ 123939219Sgibbs#endif 124039219Sgibbs default: 124139219Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 124239219Sgibbs xpt_done(ccb); 124339219Sgibbs break; 124439219Sgibbs } 124539219Sgibbs} 124639219Sgibbs 124739219Sgibbsstatic void 124839219Sgibbsahbpoll(struct cam_sim *sim) 124939219Sgibbs{ 125040132Sgibbs ahbintr(cam_sim_softc(sim)); 125139219Sgibbs} 125239219Sgibbs 125345577Seivindstatic void 125439219Sgibbsahbtimeout(void *arg) 125539219Sgibbs{ 125639219Sgibbs struct ecb *ecb; 125739219Sgibbs union ccb *ccb; 125839219Sgibbs struct ahb_softc *ahb; 125939219Sgibbs int s; 126039219Sgibbs 126139219Sgibbs ecb = (struct ecb *)arg; 126239219Sgibbs ccb = ecb->ccb; 126339219Sgibbs ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr; 126439219Sgibbs xpt_print_path(ccb->ccb_h.path); 126539390Sgibbs printf("ECB %p - timed out\n", (void *)ecb); 126639219Sgibbs 126739219Sgibbs s = splcam(); 126839219Sgibbs 126939219Sgibbs if ((ecb->state & ECB_ACTIVE) == 0) { 127039219Sgibbs xpt_print_path(ccb->ccb_h.path); 127139390Sgibbs printf("ECB %p - timed out ECB already completed\n", 127239390Sgibbs (void *)ecb); 127339219Sgibbs splx(s); 127439219Sgibbs return; 127539219Sgibbs } 127639219Sgibbs /* 127739219Sgibbs * In order to simplify the recovery process, we ask the XPT 127839219Sgibbs * layer to halt the queue of new transactions and we traverse 127939219Sgibbs * the list of pending CCBs and remove their timeouts. This 128039219Sgibbs * means that the driver attempts to clear only one error 128139219Sgibbs * condition at a time. In general, timeouts that occur 128239219Sgibbs * close together are related anyway, so there is no benefit 128339219Sgibbs * in attempting to handle errors in parrallel. Timeouts will 128439219Sgibbs * be reinstated when the recovery process ends. 128539219Sgibbs */ 128639219Sgibbs if ((ecb->state & ECB_DEVICE_RESET) == 0) { 128739219Sgibbs struct ccb_hdr *ccb_h; 128839219Sgibbs 128939219Sgibbs if ((ecb->state & ECB_RELEASE_SIMQ) == 0) { 129039219Sgibbs xpt_freeze_simq(ahb->sim, /*count*/1); 129139219Sgibbs ecb->state |= ECB_RELEASE_SIMQ; 129239219Sgibbs } 129339219Sgibbs 129439219Sgibbs ccb_h = LIST_FIRST(&ahb->pending_ccbs); 129539219Sgibbs while (ccb_h != NULL) { 129639219Sgibbs struct ecb *pending_ecb; 129739219Sgibbs 129839219Sgibbs pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr; 129939219Sgibbs untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch); 130039219Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 130139219Sgibbs } 130239219Sgibbs 130339219Sgibbs /* Store for our interrupt handler */ 130439219Sgibbs ahb->immed_ecb = ecb; 130539219Sgibbs 130639219Sgibbs /* 130739219Sgibbs * Send a Bus Device Reset message: 130839219Sgibbs * The target that is holding up the bus may not 130939219Sgibbs * be the same as the one that triggered this timeout 131039219Sgibbs * (different commands have different timeout lengths), 131139219Sgibbs * but we have no way of determining this from our 131239219Sgibbs * timeout handler. Our strategy here is to queue a 131339219Sgibbs * BDR message to the target of the timed out command. 131439219Sgibbs * If this fails, we'll get another timeout 2 seconds 131539219Sgibbs * later which will attempt a bus reset. 131639219Sgibbs */ 131739219Sgibbs xpt_print_path(ccb->ccb_h.path); 131839324Sgibbs printf("Queuing BDR\n"); 131939219Sgibbs ecb->state |= ECB_DEVICE_RESET; 132039219Sgibbs ccb->ccb_h.timeout_ch = 132139219Sgibbs timeout(ahbtimeout, (caddr_t)ecb, 2 * hz); 132239219Sgibbs 132339219Sgibbs ahb->immed_cmd = IMMED_RESET; 132439219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id); 132539219Sgibbs } else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) { 132639219Sgibbs /* 132739219Sgibbs * Try a SCSI bus reset. We do this only if we 132839219Sgibbs * have already attempted to clear the condition with a BDR. 132939219Sgibbs */ 133039219Sgibbs xpt_print_path(ccb->ccb_h.path); 133139324Sgibbs printf("Attempting SCSI Bus reset\n"); 133239219Sgibbs ecb->state |= ECB_SCSIBUS_RESET; 133339219Sgibbs ccb->ccb_h.timeout_ch = 133439219Sgibbs timeout(ahbtimeout, (caddr_t)ecb, 2 * hz); 133539219Sgibbs ahb->immed_cmd = IMMED_RESET; 133639219Sgibbs ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id); 133739219Sgibbs } else { 133839219Sgibbs /* Bring out the hammer... */ 133939219Sgibbs ahbreset(ahb); 134039219Sgibbs 134139219Sgibbs /* Simulate the reset complete interrupt */ 134239219Sgibbs ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK); 134339219Sgibbs } 134439219Sgibbs 134539219Sgibbs splx(s); 134639219Sgibbs} 134739219Sgibbs 134845791Speterstatic device_method_t ahb_eisa_methods[] = { 134945791Speter /* Device interface */ 135045791Speter DEVMETHOD(device_probe, ahbprobe), 135145791Speter DEVMETHOD(device_attach, ahbattach), 135245791Speter 135345791Speter { 0, 0 } 135445791Speter}; 135545791Speter 135645791Speterstatic driver_t ahb_eisa_driver = { 135745791Speter "ahb", 135845791Speter ahb_eisa_methods, 135945791Speter 1, /* unused */ 136045791Speter}; 136145791Speter 136245791Speterstatic devclass_t ahb_devclass; 136345791Speter 136445791SpeterDRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0); 1365