📄 ahb.c
字号:
/* * CAM SCSI device driver for the Adaptec 174X SCSI Host adapter * * Copyright (c) 1998 Justin T. Gibbs * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: ahb.c,v 1.4.2.3 1999/05/07 00:43:40 ken Exp $ */#include "eisa.h"#if NEISA > 0#include <stddef.h> /* For offsetof() */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <machine/bus_pio.h>#include <machine/bus.h>#include <machine/clock.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_sim.h>#include <cam/cam_xpt_sim.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_message.h>#include <i386/eisa/eisaconf.h>#include <i386/eisa/ahbreg.h>#define ccb_ecb_ptr spriv_ptr0#define ccb_ahb_ptr spriv_ptr1#define MIN(a, b) ((a) < (b) ? (a) : (b))#define ahb_inb(ahb, port) \ bus_space_read_1((ahb)->tag, (ahb)->bsh, port)#define ahb_inl(ahb, port) \ bus_space_read_4((ahb)->tag, (ahb)->bsh, port)#define ahb_outb(ahb, port, value) \ bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value)#define ahb_outl(ahb, port, value) \ bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value)static const char *ahbmatch(eisa_id_t type);static int ahbprobe(void);static int ahbattach(struct eisa_device *dev);static struct ahb_softc *ahballoc(u_long unit, u_int iobase, u_int irq);static void ahbfree(struct ahb_softc *ahb);static int ahbreset(struct ahb_softc *ahb);static void ahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error);static int ahbxptattach(struct ahb_softc *ahb);static void ahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat);static void ahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb);static __inline void ahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat);static void ahbintr(void *arg);static bus_dmamap_callback_t ahbexecuteecb;static void ahbaction(struct cam_sim *sim, union ccb *ccb);static void ahbpoll(struct cam_sim *sim);/* Our timeout handler */timeout_t ahbtimeout;static __inline struct ecb* ahbecbget(struct ahb_softc *ahb);static __inline void ahbecbfree(struct ahb_softc* ahb, struct ecb* ecb);static __inline u_int32_t ahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb);static __inline struct ecb* ahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr);static __inline u_int32_t ahbstatuspaddr(u_int32_t ecb_paddr);static __inline u_int32_t ahbsensepaddr(u_int32_t ecb_paddr);static __inline u_int32_t ahbsgpaddr(u_int32_t ecb_paddr);static __inline void ahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code);static __inline struct ecb*ahbecbget(struct ahb_softc *ahb){ struct ecb* ecb; int s; s = splcam(); if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL) SLIST_REMOVE_HEAD(&ahb->free_ecbs, links); splx(s); return (ecb);}static __inline voidahbecbfree(struct ahb_softc* ahb, struct ecb* ecb){ int s; s = splcam(); ecb->state = ECB_FREE; SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links); splx(s);}static __inline u_int32_tahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb){ return (ahb->ecb_physbase + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));}static __inline struct ecb*ahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr){ return (ahb->ecb_array + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase));}static __inline u_int32_tahbstatuspaddr(u_int32_t ecb_paddr){ return (ecb_paddr + offsetof(struct ecb, status));}static __inline u_int32_tahbsensepaddr(u_int32_t ecb_paddr){ return (ecb_paddr + offsetof(struct ecb, sense));}static __inline u_int32_tahbsgpaddr(u_int32_t ecb_paddr){ return (ecb_paddr + offsetof(struct ecb, sg_list));}static __inline voidahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code){ u_int loopmax = 300; while (--loopmax) { u_int status; status = ahb_inb(ahb, HOSTSTAT); if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY)) == HOSTSTAT_MBOX_EMPTY) break; DELAY(20); } if (loopmax == 0) panic("ahb%ld: adapter not taking commands\n", ahb->unit); ahb_outl(ahb, MBOXOUT0, mboxval); ahb_outb(ahb, ATTN, attn_code);}static u_long ahbunit;static struct eisa_driver ahb_eisa_driver ={ "ahb", ahbprobe, ahbattach, /*shutdown*/NULL, &ahbunit};DATA_SET (eisadriver_set, ahb_eisa_driver);static const char *ahbmatch(eisa_id_t type){ switch(type & 0xfffffe00) { case EISA_DEVICE_ID_ADAPTEC_1740: return ("Adaptec 174x SCSI host adapter"); break; default: break; } return (NULL);} static intahbprobe(void) { struct eisa_device *e_dev = NULL; u_int32_t iobase; u_int32_t irq; int count; count = 0; while ((e_dev = eisa_match_dev(e_dev, ahbmatch))) { u_int8_t intdef; iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) + AHB_EISA_SLOT_OFFSET; eisa_add_iospace(e_dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE); intdef = inb(INTDEF + iobase); switch (intdef & 0x7) { case INT9: irq = 9; break; case INT10: irq = 10; break; case INT11: irq = 11; break; case INT12: irq = 12; break; case INT14: irq = 14; break; case INT15: irq = 15; break; default: printf("Adaptec 174X at slot %d: illegal " "irq setting %d\n", e_dev->ioconf.slot, (intdef & 0x7)); irq = 0; break; } if (irq == 0) continue; eisa_add_intr(e_dev, irq); eisa_registerdev(e_dev, &ahb_eisa_driver); count++; } return count; }static intahbattach(struct eisa_device *e_dev){ /* * find unit and check we have that many defined */ struct ahb_softc *ahb; struct ecb* next_ecb; resvaddr_t *iospace; u_int irq; if (TAILQ_FIRST(&e_dev->ioconf.irqs) == NULL) return (-1); irq = TAILQ_FIRST(&e_dev->ioconf.irqs)->irq_no; iospace = e_dev->ioconf.ioaddrs.lh_first; if (iospace == NULL) return (-1); eisa_reg_start(e_dev); if (eisa_reg_iospace(e_dev, iospace)) { eisa_reg_end(e_dev); return (-1); } if ((ahb = ahballoc(e_dev->unit, iospace->addr, irq)) == NULL) { eisa_reg_end(e_dev); return (-1); } if (ahbreset(ahb) != 0) return (-1); if (eisa_reg_intr(e_dev, irq, ahbintr, (void *)ahb, &cam_imask, (ahb_inb(ahb, INTDEF) & INTLEVEL) ? TRUE : FALSE)) { eisa_reg_end(e_dev); ahbfree(ahb); return (-1); } /* * Create our DMA tags. These tags define the kinds of device * accessable memory allocations and memory mappings we will * need to perform during normal operation. */ /* DMA tag for mapping buffers into device visible space. */ /* XXX Should be a child of the EISA bus dma tag */ if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/MAXBSIZE, /*nsegments*/AHB_NSEG, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/BUS_DMA_ALLOCNOW, &ahb->buffer_dmat) != 0) goto error_exit; ahb->init_level++; /* DMA tag for our ccb structures and ha inquiry data */ if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, (AHB_NECB * sizeof(struct ecb)) + sizeof(*ahb->ha_inq_data), /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &ahb->ecb_dmat) != 0) goto error_exit; ahb->init_level++; /* Allocation for our ccbs */ if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array, BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0) goto error_exit; ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB]; ahb->init_level++; /* And permanently map them */ bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap, ahb->ecb_array, AHB_NSEG * sizeof(struct ecb), ahbmapecbs, ahb, /*flags*/0); ahb->init_level++; /* Allocate the buffer dmamaps for each of our ECBs */ bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb)) + sizeof(*ahb->ha_inq_data)); next_ecb = ahb->ecb_array; while (ahb->num_ecbs < AHB_NECB) { u_int32_t ecb_paddr; if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0, &next_ecb->dmamap)) break; ecb_paddr = ahbecbvtop(ahb, next_ecb); next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr); next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr); ahb->num_ecbs++; ahbecbfree(ahb, next_ecb); next_ecb++; } if (ahb->num_ecbs == 0) goto error_exit; ahb->init_level++; eisa_reg_end(e_dev); /* * Now that we know we own the resources we need, register * our bus with the XPT. */ if (ahbxptattach(ahb)) goto error_exit; /* Enable our interrupt */ eisa_enable_intr(e_dev, irq); return (0);error_exit: /* * The board's IRQ line will not be left enabled * if we can't intialize correctly, so its safe * to release the irq. */ eisa_release_intr(e_dev, irq, ahbintr); ahbfree(ahb); return (-1);}static struct ahb_softc *ahballoc(u_long unit, u_int iobase, u_int irq){ struct ahb_softc *ahb; /* * Allocate a storage area for us */ ahb = malloc(sizeof(struct ahb_softc), M_TEMP, M_NOWAIT); if (!ahb) { printf("ahb%ld: cannot malloc!\n", unit); return (NULL); } bzero(ahb, sizeof(struct ahb_softc)); SLIST_INIT(&ahb->free_ecbs); LIST_INIT(&ahb->pending_ccbs); ahb->unit = unit; ahb->tag = I386_BUS_SPACE_IO; ahb->bsh = iobase; ahb->disc_permitted = ~0; ahb->tags_permitted = ~0; return (ahb);}static void ahbfree(struct ahb_softc *ahb){ switch (ahb->init_level) { default: case 4: bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap); case 3: bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array, ahb->ecb_dmamap); bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap); case 2: bus_dma_tag_destroy(ahb->ecb_dmat); case 1: bus_dma_tag_destroy(ahb->buffer_dmat); case 0: } free(ahb, M_DEVBUF);}/* * reset board, If it doesn't respond, return failure */static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -