ahc_eisa.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 474 行
C
474 行
/* * Product specific probe and attach routines for: * 27/284X and aic7770 motherboard SCSI controllers * * Copyright (c) 1994, 1995, 1996, 1997, 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: ahc_eisa.c,v 1.4.2.2 1999/05/16 00:07:57 gibbs Exp $ */#include "eisa.h"#if NEISA > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <machine/bus_pio.h>#include <machine/bus.h>#include <i386/eisa/eisaconf.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_sim.h>#include <cam/cam_xpt_sim.h>#include <cam/scsi/scsi_all.h>#include <dev/aic7xxx/aic7xxx.h>#include <dev/aic7xxx/93cx6.h>#include <aic7xxx_reg.h>#define EISA_DEVICE_ID_ADAPTEC_AIC7770 0x04907770#define EISA_DEVICE_ID_ADAPTEC_274x 0x04907771#define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */#define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/#define AHC_EISA_SLOT_OFFSET 0xc00#define AHC_EISA_IOSIZE 0x100#define INTDEF 0x5cul /* Interrupt Definition Register */static int aic7770_probe(void);static int aic7770_attach(struct eisa_device *e_dev); static void aha2840_load_seeprom(struct ahc_softc *ahc);static struct eisa_driver ahc_eisa_driver ={ "ahc", aic7770_probe, aic7770_attach, /*shutdown*/NULL, &ahc_unit};DATA_SET (eisadriver_set, ahc_eisa_driver);static const char *aic7770_match(eisa_id_t type);static const char*aic7770_match(eisa_id_t type){ switch (type) { case EISA_DEVICE_ID_ADAPTEC_AIC7770: return ("Adaptec aic7770 SCSI host adapter"); break; case EISA_DEVICE_ID_ADAPTEC_274x: return ("Adaptec 274X SCSI host adapter"); break; case EISA_DEVICE_ID_ADAPTEC_284xB: case EISA_DEVICE_ID_ADAPTEC_284x: return ("Adaptec 284X SCSI host adapter"); break; default: break; } return (NULL);}static intaic7770_probe(){ u_int32_t iobase; u_int32_t irq; u_int8_t intdef; u_int8_t hcntrl; struct eisa_device *e_dev; int count; e_dev = NULL; count = 0; while ((e_dev = eisa_match_dev(e_dev, aic7770_match))) { iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) + AHC_EISA_SLOT_OFFSET; /* Pause the card preseving the IRQ type */ hcntrl = inb(iobase + HCNTRL) & IRQMS; outb(iobase + HCNTRL, hcntrl | PAUSE); eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE); intdef = inb(INTDEF + iobase); irq = intdef & 0xf; switch (irq) { case 9: case 10: case 11: case 12: case 14: case 15: break; default: printf("aic7770 at slot %d: illegal " "irq setting %d\n", e_dev->ioconf.slot, intdef); irq = 0; break; } if (irq == 0) continue; eisa_add_intr(e_dev, irq); eisa_registerdev(e_dev, &ahc_eisa_driver); count++; } return count;}static intaic7770_attach(struct eisa_device *e_dev){ ahc_chip chip; bus_dma_tag_t parent_dmat; struct ahc_softc *ahc; resvaddr_t *iospace; int unit = e_dev->unit; int irq; int error; 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) return -1; switch (e_dev->id) { case EISA_DEVICE_ID_ADAPTEC_274x: case EISA_DEVICE_ID_ADAPTEC_AIC7770: chip = AHC_AIC7770|AHC_EISA; break; case EISA_DEVICE_ID_ADAPTEC_284xB: case EISA_DEVICE_ID_ADAPTEC_284x: chip = AHC_AIC7770|AHC_VL; break; default: printf("aic7770_attach: Unknown device type!\n"); return -1; } /* XXX Should be a child of the EISA bus dma tag */ error = 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*/AHC_NSEG, /*maxsegsz*/AHC_MAXTRANSFER_SIZE, /*flags*/BUS_DMA_ALLOCNOW, &parent_dmat); if (error != 0) { printf("ahc_eisa_attach: Could not allocate DMA tag " "- error %d\n", error); return -1; } if (!(ahc = ahc_alloc(unit, iospace->addr, NULL, parent_dmat, chip, AHC_AIC7770_FE, AHC_FNONE, NULL))) return -1; ahc->channel = 'A'; ahc->channel_b = 'B'; eisa_reg_start(e_dev); if (eisa_reg_iospace(e_dev, iospace)) { ahc_free(ahc); return -1; } if (ahc_reset(ahc) != 0) { ahc_free(ahc); return -1; } /* * The IRQMS bit enables level sensitive interrupts. Only allow * IRQ sharing if it's set. */ if (eisa_reg_intr(e_dev, irq, ahc_intr, (void *)ahc, &cam_imask, /*shared ==*/ahc->pause & IRQMS)) { ahc_free(ahc); return -1; } eisa_reg_end(e_dev); /* * Tell the user what type of interrupts we're using. * usefull for debugging irq problems */ if (bootverbose) { printf("%s: Using %s Interrupts\n", ahc_name(ahc), ahc->pause & IRQMS ? "Level Sensitive" : "Edge Triggered"); } /* * Now that we know we own the resources we need, do the * card initialization. * * First, the aic7770 card specific setup. */ switch (chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: { u_int biosctrl; u_int scsiconf; u_int scsiconf1;#if DEBUG int i;#endif biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); scsiconf = ahc_inb(ahc, SCSICONF); scsiconf1 = ahc_inb(ahc, SCSICONF + 1);#if DEBUG for (i = TARG_SCSIRATE; i <= HA_274_BIOSCTRL; i+=8) { printf("0x%x, 0x%x, 0x%x, 0x%x, " "0x%x, 0x%x, 0x%x, 0x%x\n", ahc_inb(ahc, i), ahc_inb(ahc, i+1), ahc_inb(ahc, i+2), ahc_inb(ahc, i+3), ahc_inb(ahc, i+4), ahc_inb(ahc, i+5), ahc_inb(ahc, i+6), ahc_inb(ahc, i+7)); }#endif /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) ahc->flags |= AHC_CHANNEL_B_PRIMARY; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; } else { if ((ahc->features & AHC_WIDE) != 0) { ahc->our_id = scsiconf1 & HWSCSIID; if (scsiconf & TERM_ENB) ahc->flags |= AHC_TERM_ENB_A; } else { ahc->our_id = scsiconf & HSCSIID; ahc->our_id_b = scsiconf1 & HSCSIID; if (scsiconf & TERM_ENB) ahc->flags |= AHC_TERM_ENB_A; if (scsiconf1 & TERM_ENB) ahc->flags |= AHC_TERM_ENB_B; } } /* * We have no way to tell, so assume extended * translation is enabled. */ ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; break; } case AHC_VL: { aha2840_load_seeprom(ahc); break; } default: break; } /* * See if we have a Rev E or higher aic7770. Anything below a * Rev E will have a R/O autoflush disable configuration bit. */ { char *id_string; u_int8_t sblkctl; u_int8_t sblkctl_orig; sblkctl_orig = ahc_inb(ahc, SBLKCTL); sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; ahc_outb(ahc, SBLKCTL, sblkctl); sblkctl = ahc_inb(ahc, SBLKCTL); if (sblkctl != sblkctl_orig) { id_string = "aic7770 >= Rev E, "; /* * Ensure autoflush is enabled */ sblkctl &= ~AUTOFLUSHDIS; ahc_outb(ahc, SBLKCTL, sblkctl); } else id_string = "aic7770 <= Rev C, "; printf("%s: %s", ahc_name(ahc), id_string); } /* Setup the FIFO threshold and the bus off time */ { u_int8_t hostconf = ahc_inb(ahc, HOSTCONF); ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); } /* * Generic aic7xxx initialization. */ if (ahc_init(ahc)) { ahc_free(ahc); /* * The board's IRQ line is not yet enabled so it's safe * to release the irq. */ eisa_release_intr(e_dev, irq, ahc_intr); return -1; } /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); /* * Enable our interrupt handler. */ if (eisa_enable_intr(e_dev, irq)) { ahc_free(ahc); eisa_release_intr(e_dev, irq, ahc_intr); return -1; } /* Attach sub-devices - always succeeds */ ahc_attach(ahc); return 0;}/* * Read the 284x SEEPROM. */static voidaha2840_load_seeprom(struct ahc_softc *ahc){ struct seeprom_descriptor sd; struct seeprom_config sc; u_int16_t checksum = 0; u_int8_t scsi_conf; int have_seeprom; sd.sd_tag = ahc->tag; sd.sd_bsh = ahc->bsh; sd.sd_control_offset = SEECTL_2840; sd.sd_status_offset = STATUS_2840; sd.sd_dataout_offset = STATUS_2840; sd.sd_chip = C46; sd.sd_MS = 0; sd.sd_RDY = EEPROM_TF; sd.sd_CS = CS_2840; sd.sd_CK = CK_2840; sd.sd_DO = DO_2840; sd.sd_DI = DI_2840; if (bootverbose) printf("%s: Reading SEEPROM...", ahc_name(ahc)); have_seeprom = read_seeprom(&sd, (u_int16_t *)&sc, /*start_addr*/0, sizeof(sc)/2); if (have_seeprom) { /* Check checksum */ int i; int maxaddr = (sizeof(sc)/2) - 1; u_int16_t *scarray = (u_int16_t *)≻ for (i = 0; i < maxaddr; i++) checksum = checksum + scarray[i]; if (checksum != sc.checksum) { if(bootverbose) printf ("checksum error\n"); have_seeprom = 0; } else if (bootverbose) { printf("done.\n"); } } if (!have_seeprom) { if (bootverbose) printf("%s: No SEEPROM available\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; } else { /* * Put the data we've collected down into SRAM * where ahc_init will find it. */ int i; int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; u_int16_t discenable; discenable = 0; for (i = 0; i < max_targ; i++){ u_int8_t target_settings; target_settings = (sc.device_flags[i] & CFXFER) << 4; if (sc.device_flags[i] & CFSYNCH) target_settings |= SOFS; if (sc.device_flags[i] & CFWIDEB) target_settings |= WIDEXFER; if (sc.device_flags[i] & CFDISC) discenable |= (0x01 << i); ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); } ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); ahc->our_id = sc.brtime_id & CFSCSIID; scsi_conf = (ahc->our_id & 0x7); if (sc.adapter_control & CFSPARITY) scsi_conf |= ENSPCHK; if (sc.adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; if (sc.bios_control & CF284XEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; /* Set SCSICONF info */ ahc_outb(ahc, SCSICONF, scsi_conf); if (sc.adapter_control & CF284XSTERM) ahc->flags |= AHC_TERM_ENB_A; }}#endif /* NEISA > 0 */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?