📄 esp.c
字号:
#ident "@(#)esp.c 1.1 92/07/30 SMI"/* * Copyright (c) 1988-1991 by Sun Microsystems, Inc. */#include "esp.h"#if NESP > 0#include <scsi/scsi.h>#include <scsi/adapters/espvar.h>#ifdef OPENPROMS#include <sun/autoconf.h>#endif /* OPENPROMS */#ifdef sun4m#include <sun4m/iommu.h>#endif /* sun4m *//* * Update Grok- to allow compilation on systems without newer dmaga.h header(s) */#ifndef BURSTSIZE#define BURSTSIZE#define BURST1 0x01#define BURST2 0x02#define BURST4 0x04#define BURST8 0x08#define BURST16 0x10#define BURST32 0x20#define BURST64 0x40#define BURSTSIZE_MASK 0x7f#define DEFAULT_BURSTSIZE BURST16|BURST8|BURST4|BURST2|BURST1#endif /* BURSTSIZE */#ifndef DMAGA_TURBO#define DMAGA_TURBO 0x00400000#endif /* !DMAGA_TURBO */#ifndef ESC1_REV1#define ESC1_REV1 0x4#define SET_DMAESC_COUNT(dmar, val) (dmar)->dmaga_count = val#define DMAESC_BSIZE 0x0800#define DMAESC_TCZERO 0x1000#define DMAESC_EN_TCI 0x2000#define DMAESC_INTPEND 0x4000#define DMAESC_PEN 0x8000#define DMAESC_PERR 0x00010000#define DMAESC_DRAIN 0x00020000#define DMAESC_EN_ADD 0x00040000#define DMAESC_SETBURST16(d) (d)->dmaga_csr |= DMAESC_BSIZE#define DMAESC_SETBURST32(d) (d)->dmaga_csr &= ~DMAESC_BSIZE#endif /* ESC1_REV1 */#ifndef DMA_REV3#define DMA_REV3 0xA /* DMA2 gate array */#define DMAGA_BURSTMASK 0x000C0000#define DMAGA_BURST16 0x00000000#define DMAGA_NOBURST 0x00080000#define DMAGA_BURST32 0x00040000#define DMA2_SETNOBURST(d) \ (d)->dmaga_csr &= ~DMAGA_BURSTMASK, (d)->dmaga_csr |= DMAGA_NOBURST#define DMA2_SETBURST16(d) (d)->dmaga_csr &= ~DMAGA_BURSTMASK#define DMA2_SETBURST32(d) \ (d)->dmaga_csr &= ~DMAGA_BURSTMASK, (d)->dmaga_csr |= DMAGA_BURST32#define DMAGA_TWO_CYCLE 0x00200000#endif /* !DMA_REV3 *//* * Local function declarations */static int esp_start(), esp_abort(), esp_reset(), esp_getcap(), esp_setcap();static int esp_poll(), esp_watch(), esp_phasemanage();static int esp_finish_select(), esp_reconnect(), esp_finish();static int esp_ustart(), esp_startcmd(), esp_reset_recovery(), esp_istart();static int esp_abort_curcmd(), esp_abort_allcmds(), esp_reset_bus();static int esp_handle_selection();static int esp_dopoll();#ifdef VECTORED_INTERRUPTSstatic int esp_intr();#endif /* VECTORED_INTERRUPTS */static void esp_internal_reset(), esp_sync_backoff();static void esp_hw_reset(), esp_curcmd_timeout(), esp_disccmd_timeout();static void esplog(), eprintf(), esp_stat_int_print();static void esp_watchsubr();static void espsvc();static void esp_dump_datasegs(), esp_dump_cmd();static void esp_chip_disconnect();static void esp_makeproxy_cmd(), esp_make_sdtr();static void esp_init_cmd(), esp_runpoll();/* * Phase handlers */static int esp_handle_unknown(), esp_handle_cmd_start(), esp_handle_cmd_done();static int esp_handle_msg_out(), esp_handle_msg_out_done();static int esp_handle_clearing();static int esp_handle_msg_in(), esp_handle_more_msgin();static int esp_handle_msg_in_done();static int esp_handle_c_cmplt(), esp_handle_data(), esp_handle_data_done();/* * Debug routines- ultimately to be hidden within ESPDEBUG */#ifdef ESPDEBUGstatic void esp_dump_state();#endif /* ESPDEBUG */static void esp_printstate();static char *esp_state_name();/* * Local static data */static int espconf = 0;static int espconf2 = 0;static int espconf3 = 0;#define POLL_TIMEOUT (3 * 60000000) /* in usec, about 3 mins */static struct esp *esp_softc = (struct esp *) 0;#ifdef OPENPROMSstatic int nesp;#else /* OPENPROMS */static int nesp = NESP;#endif /* OPENPROMS */static char *esp_stat_bits = ESP_STAT_BITS;static char *esp_int_bits = ESP_INT_BITS;static char *dmaga_bits = DMAGA_BITS;static char *msginperr = "SCSI bus MESSAGE IN phase parity error\n";#ifdef sun4cstatic int esp_ss1_esp0sync = 0;#endif /* sun4c */static int esp_nhardints;static int esp_nmultsvc;#ifdef ESPDEBUGstatic int espdebug = 0;#endif /* ESPDEBUG */#ifdef ESP_TEST_PARITYstatic int esp_ptest_msgin;static int esp_ptest_msg = -1;static int esp_ptest_msgcmplt;static int esp_ptest_status;static int esp_ptest_data_in;#endif /* ESP_TEST_PARITY */#ifdef ESP_TEST_TIMEOUTstatic int esp_ttest;static int esp_stest;#endif /* ESP_TEST_TIMEOUT *//* * autoconfiguration routines. */#ifdef OPENPROMSstatic int esp_identify(), esp_attach();struct dev_ops esp_ops = { 1, esp_identify, esp_attach};#ifdef GASPextern int gasp_cards;extern u_long gasp_addrs[];#define ESP_OFFSET 0x800000#define Esp_addr(card) (gasp_addrs[(card)] + ESP_OFFSET)static voidnew_esp(prev, gaddr)struct dev_info *prev;u_long gaddr;{ struct dev_info *dev; dev = (struct dev_info *) kmem_zalloc (sizeof (*dev)); dev->devi_parent = prev->devi_parent; dev->devi_next = prev->devi_next; prev->devi_next = dev; dev->devi_name = prev->devi_name; dev->devi_nreg = 1; dev->devi_reg = (struct dev_reg *) kmem_zalloc(sizeof (struct dev_reg)); dev->devi_reg->reg_bustype = OBIO; dev->devi_reg->reg_addr = (addr_t) gaddr; dev->devi_reg->reg_size = sizeof (struct espreg); dev->devi_nintr = 1; dev->devi_intr = prev->devi_intr; dev->devi_driver = &esp_ops; dev->devi_nodeid = prev->devi_nodeid; /* lies. all lies */ nesp += 1;}#endif /* GASP */static intesp_identify(name) char *name;{ /* * Note the octal literal for a comma. * Avoids Shannon's C-style awk script's complaints */ if (strcmp(name, "esp") == 0 || strcmp(name, "SUNW\054esp") == 0) { nesp++; return (1); } else { return (0); }}static intesp_attach(dev)register struct dev_info *dev;{#ifdef ESP_NEW_HW_DEBUG static char *cdebug = "esp%d: %s %s returned as %d\n";#endif /* ESP_NEW_HW_DEBUG */ static char *prop_ini_id = "initiator-id"; static char *prop_scsi_ini_id = "scsi-initiator-id"; static char *prop_cfreq = "clock-frequency"; static char *prop_bur_size = "burst-sizes"; static char *prop_diff = "differential"; static int next_unit = 0; static int esp_spl = 0; register struct dmaga *dmar; register struct espreg *ep; register struct esp *esp, *nsp; register struct dev_info *ndev; int i, cur_unit; u_long ticks; u_char clock_conv;#ifdef GASP if (next_unit == 0) { register card; struct dev_info *tmp = dev; for (card = 0; card < 4; card++) { if (gasp_cards & (1<<card)) { new_esp(tmp, Esp_addr(card)); tmp = tmp->devi_next; } } }#endif /* GASP */ cur_unit = dev->devi_unit = next_unit++; if (cur_unit >= nesp || dev->devi_nreg > 1 || dev->devi_nintr == 0) { return (-1); }#ifdef sun4c /* * Check to see whether this is a useful * slot for an sbus scsi interface */ if ((i = slaveslot(dev->devi_reg->reg_addr)) >= 0) { printf("esp%d: not used - SBus slot %d is slave-only\n", cur_unit, i); return (-1); }#endif /* sun4c */ /* * map in device registers */ ep = (struct espreg *) map_regs(dev->devi_reg->reg_addr, dev->devi_reg->reg_size, dev->devi_reg->reg_bustype); if (ep == (struct espreg *) 0) { printf("esp%d: unable to map registers\n", cur_unit); return (-1); } dmar = dma_alloc(dev->devi_reg->reg_bustype, dev->devi_reg->reg_addr); if (!dmar) { printf("esp%d: cannot find dma controller\n", cur_unit); unmap_regs((addr_t) ep, dev->devi_reg->reg_size); return (-1); } /* * Initialize state of DMA gate array. * Must clear DMAGA_RESET on the ESC before accessing the esp. */ if (DMAGA_REV(dmar) == ESC1_REV1) { dmar->dmaga_csr &= ~DMAGA_RESET; } dmar->dmaga_csr &= ~DMAGA_WRITE; /* * If we haven't allocated the softc structure, do so now. */ esp = (struct esp *) kmem_zalloc((unsigned) (sizeof (struct esp))); if (esp != (struct esp *) 0) { esp->e_cmdarea = (u_char *) IOPBALLOC(FIFOSIZE); } if (esp == (struct esp *) 0 || esp->e_cmdarea == (u_char *) 0) { printf("esp%d: no space for %s\n", cur_unit, (esp->e_cmdarea) ? "cmd areas" : "data structures"); if (esp) { (void) kmem_free((caddr_t)esp, (sizeof (struct esp))); } unmap_regs((addr_t) ep, dev->devi_reg->reg_size); dma_free(dmar); return (-1); } esp->e_next = (struct esp *) 0; esp->e_unit = cur_unit; /* * Establish initial softc values */ if (esp_softc == (struct esp *) 0) { esp_softc = esp; timeout (esp_watch, (caddr_t) 0, hz); } else { for (nsp = esp_softc; nsp->e_next != (struct esp *) 0; nsp = nsp->e_next); nsp->e_next = esp; } /* * Determine clock frequency of attached ESP chip. */ for (ndev = dev; ndev; ndev = ndev->devi_parent) { i = getprop(ndev->devi_nodeid, prop_cfreq, -1); if ((i > 0) || ndev == top_devinfo) {#ifdef ESP_NEW_HW_DEBUG printf (cdebug, cur_unit, ndev->devi_name, prop_cfreq, i);#endif /* ESP_NEW_HW_DEBUG */ break; } }#ifdef ESP_NEW_HW_DEBUG if (i != 40000000) { printf("WARNING: found clock frequency of %d\n", i); printf(" Assuming clock frequency of 40 MHZ\n"); i = 40000000; }#endif /* ESP_NEW_HW_DEBUG */ /* * Valid clock freqs. are between 10 and 40 MHz. Otherwise * presume 20 MHz. and complain. (Notice, that we wrap to * zero at 40 MHz. Ick!) This test should NEVER fail! * * freq (MHz) clock conversion factor * 10 2 * 10.01-15 3 * 15.01-20 4 * 20.01-25 5 * 25.01-30 6 * 30.01-35 7 * 35.01-40 8 (0) */ if (i > FIVE_MEG) { clock_conv = (i + FIVE_MEG - 1)/ FIVE_MEG; } else { clock_conv = 0; } if (clock_conv < CLOCK_10MHZ || clock_conv > CLOCK_40MHZ) { esplog(esp, LOG_ERR, "Bad clock frequency- setting 20mhz, asynchronous mode"); esp->e_weak = 0xff; clock_conv = CLOCK_20MHZ; i = TWENTY_MEG; } esp->e_clock_conv = clock_conv; esp->e_clock_cycle = CLOCK_PERIOD(i); ticks = ESP_CLOCK_TICK(esp); esp->e_stval = ESP_CLOCK_TIMEOUT(ticks);#ifdef ESP_TEST_FAST_SYNC IPRINTF5("%d mhz, clock_conv %d, clock_cycle %d, ticks %d, stval %d\n", i, esp->e_clock_conv, esp->e_clock_cycle, ticks, esp->e_stval);#endif ESP_TEST_FAST_SYNC /* * The theory is that the layout of all cpu boards post SparcStation-1 * is clean enough to allow SYNC mode to be on all the time. */#ifdef sun4c if (cpu == CPU_SUN4C_60 && dev->devi_unit == 0 && esp_ss1_esp0sync == 0) { esp->e_weak = 0xff; }#endif /* sun4c */ /* * Calculate max locking spl so far seen.. */ esp->e_spl = ipltospl(dev->devi_intr->int_pri); esp_spl = MAX(esp_spl, esp->e_spl); /* * Make sure that everyone, including us, is locking at * the same priority. */ for (nsp = esp_softc; nsp != (struct esp *) 0; nsp = nsp->e_next) nsp->e_tran.tran_spl = esp_spl;#ifdef ESPDEBUG /* * Initialize last state log. */ for (i = 0; i < NPHASE; i++) { esp->e_phase[i].e_save_state = STATE_FREE; esp->e_phase[i].e_save_stat = -1; esp->e_phase[i].e_val1 = -1; esp->e_phase[i].e_val2 = -1; } esp->e_phase_index = 0; esp->e_xfer = 0;#endif /* ESPDEBUG */ esp->e_tran.tran_start = esp_start; esp->e_tran.tran_abort = esp_abort; esp->e_tran.tran_reset = esp_reset; esp->e_tran.tran_getcap = esp_getcap; esp->e_tran.tran_setcap = esp_setcap; esp->e_tran.tran_pktalloc = scsi_std_pktalloc; esp->e_tran.tran_dmaget = scsi_std_dmaget; esp->e_tran.tran_pktfree = scsi_std_pktfree; esp->e_tran.tran_dmafree = scsi_std_dmafree; esp->e_dev = dev; esp->e_espconf = DEFAULT_HOSTID; for (ndev = dev; ndev; ndev = ndev->devi_parent) { i = getprop(ndev->devi_nodeid, prop_ini_id, -1);#ifdef ESP_NEW_HW_DEBUG printf (cdebug, cur_unit, ndev->devi_name, prop_ini_id, i);#endif /* ESP_NEW_HW_DEBUG */ if (i == -1) { i = getprop(ndev->devi_nodeid, prop_scsi_ini_id, -1);#ifdef ESP_NEW_HW_DEBUG printf (cdebug, cur_unit, ndev->devi_name, prop_scsi_ini_id, i);#endif /* ESP_NEW_HW_DEBUG */ } if (i != DEFAULT_HOSTID && i >= 0 && i <= 7) { esplog(esp, LOG_INFO, "initiator SCSI Id now %d", i); esp->e_espconf = (u_char) i; } if (i > -1 || ndev == top_devinfo) break; } if (scsi_options & SCSI_OPTIONS_PARITY) esp->e_espconf |= ESP_CONF_PAREN; esp->e_espconf |= (espconf & ~ESP_CONF_BUSID); esp->e_reg = ep; esp->e_dma = dmar; /* * Determine sbus burst size. * top_devinfo is declared in <sun/openprom.h>. */ esp->e_burstsizes = 0xff; ndev = esp->e_dev; do { i = getprop(ndev->devi_nodeid, prop_bur_size, -1); if (i != -1) { /* * oops- we have somebody who constrains us. */ esp->e_burstsizes = esp->e_burstsizes & i;#ifdef ESP_NEW_HW_DEBUG printf (cdebug, cur_unit, ndev->devi_name, prop_bur_size, i);#endif /* ESP_NEW_HW_DEBUG */ } ndev = ndev->devi_parent; } while (ndev != top_devinfo); /* * No burstsize properties found- select a reasonable default */ i = esp->e_burstsizes; if ((i == 0xff) || (!((i & BURST16) || (i & BURST32)))) {#ifdef ESPDEBUG if (DEBUGGING) { eprintf(esp, "Bad burst size %d- setting to %d", i, DEFAULT_BURSTSIZE); }#endif /* ESPDEBUG */ esp->e_burstsizes = DEFAULT_BURSTSIZE; } /* * XXX: This needs to be based upon architecture. Right now, * XXX: all OPENPROM machines are sun4c and have a dma base * XXX: of -1mb. */ esp->e_dma_base = (u_long) DVMA; esp->e_last_slot = esp->e_cur_slot = UNDEFINED; addintr(dev->devi_intr->int_pri, esp_poll, dev->devi_name, dev->devi_unit); adddma(dev->devi_intr->int_pri); report_dev(dev); ep->esp_conf2 = 0; ep->esp_conf2 = 0xa; esp->e_default_period = CONVERT_PERIOD(DEFAULT_SYNC_PERIOD); if ((ep->esp_conf2&0xf) == 0xa) { esp->e_espconf2 = espconf2; ep->esp_conf3 = 0; ep->esp_conf3 = 5; if (ep->esp_conf3 == 0x5) { for (i = 0; i < NTARGETS; i++) { esp->e_espconf3[i] = espconf3; } if (clock_conv > CLOCK_25MHZ) { esp->e_espconf2 |= ESP_CONF2_FENABLE; ep->esp_conf2 = esp->e_espconf2; esp->e_default_period = CONVERT_PERIOD(DEFAULT_FASTSYNC_PERIOD); esp->e_type = FAST;#ifdef ESP_TEST_FAST_SYNC IPRINTF1("conf3=%x\n", espconf3); IPRINTF("found FAST\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -