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