📄 uda.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)uda.c 7.32 (Berkeley) 2/13/91 *//* * UDA50/MSCP device driver */#define POLLSTATS/* * TODO * write bad block forwarding code */#include "ra.h"#if NUDA > 0/* * CONFIGURATION OPTIONS. The next three defines are tunable -- tune away! * * COMPAT_42 enables 4.2/4.3 compatibility (label mapping) * * NRSPL2 and NCMDL2 control the number of response and command * packets respectively. They may be any value from 0 to 7, though * setting them higher than 5 is unlikely to be of any value. * If you get warnings about your command ring being too small, * try increasing the values by one. * * MAXUNIT controls the maximum unit number (number of drives per * controller) we are prepared to handle. * * DEFAULT_BURST must be at least 1. */#define COMPAT_42#define NRSPL2 5 /* log2 number of response packets */#define NCMDL2 5 /* log2 number of command packets */#define MAXUNIT 8 /* maximum allowed unit number */#define DEFAULT_BURST 4 /* default DMA burst size */#include "sys/param.h"#include "sys/systm.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/file.h"#include "sys/ioctl.h"#include "sys/user.h"#include "sys/map.h"#include "sys/vm.h"#include "sys/dkstat.h"#include "sys/cmap.h"#include "sys/disklabel.h"#include "sys/syslog.h"#include "sys/stat.h"#include "../include/pte.h"#include "../include/cpu.h"#include "ubareg.h"#include "ubavar.h"#define NRSP (1 << NRSPL2)#define NCMD (1 << NCMDL2)#include "udareg.h"#include "../vax/mscp.h"#include "../vax/mscpvar.h"#include "../include/mtpr.h"/* * UDA communications area and MSCP packet pools, per controller. */struct uda { struct udaca uda_ca; /* communications area */ struct mscp uda_rsp[NRSP]; /* response packets */ struct mscp uda_cmd[NCMD]; /* command packets */} uda[NUDA];/* * Software status, per controller. */struct uda_softc { struct uda *sc_uda; /* Unibus address of uda struct */ short sc_state; /* UDA50 state; see below */ short sc_flags; /* flags; see below */ int sc_micro; /* microcode revision */ int sc_ivec; /* interrupt vector address */ short sc_ipl; /* interrupt priority, Q-bus */ struct mscp_info sc_mi;/* MSCP info (per mscpvar.h) */#ifndef POLLSTATS int sc_wticks; /* watchdog timer ticks */#else short sc_wticks; short sc_ncmd;#endif} uda_softc[NUDA];#ifdef POLLSTATSstruct udastats { int ncmd; int cmd[NCMD + 1];} udastats = { NCMD + 1 };#endif/* * Controller states */#define ST_IDLE 0 /* uninitialised */#define ST_STEP1 1 /* in `STEP 1' */#define ST_STEP2 2 /* in `STEP 2' */#define ST_STEP3 3 /* in `STEP 3' */#define ST_SETCHAR 4 /* in `Set Controller Characteristics' */#define ST_RUN 5 /* up and running *//* * Flags */#define SC_MAPPED 0x01 /* mapped in Unibus I/O space */#define SC_INSTART 0x02 /* inside udastart() */#define SC_GRIPED 0x04 /* griped about cmd ring too small */#define SC_INSLAVE 0x08 /* inside udaslave() */#define SC_DOWAKE 0x10 /* wakeup when ctlr init done */#define SC_STARTPOLL 0x20 /* need to initiate polling *//* * Device to unit number and partition and back */#define UNITSHIFT 3#define UNITMASK 7#define udaunit(dev) (minor(dev) >> UNITSHIFT)#define udapart(dev) (minor(dev) & UNITMASK)#define udaminor(u, p) (((u) << UNITSHIFT) | (p))/* * Drive status, per drive */struct ra_info { daddr_t ra_dsize; /* size in sectors *//* u_long ra_type; /* drive type */ u_long ra_mediaid; /* media id */ int ra_state; /* open/closed state */ struct ra_geom { /* geometry information */ u_short rg_nsectors; /* sectors/track */ u_short rg_ngroups; /* track groups */ u_short rg_ngpc; /* groups/cylinder */ u_short rg_ntracks; /* ngroups*ngpc */ u_short rg_ncyl; /* ra_dsize/ntracks/nsectors */#ifdef notyet u_short rg_rctsize; /* size of rct */ u_short rg_rbns; /* replacement blocks per track */ u_short rg_nrct; /* number of rct copies */#endif } ra_geom; int ra_wlabel; /* label sector is currently writable */ u_long ra_openpart; /* partitions open */ u_long ra_bopenpart; /* block partitions open */ u_long ra_copenpart; /* character partitions open */} ra_info[NRA];/* * Software state, per drive */#define CLOSED 0#define WANTOPEN 1#define RDLABEL 2#define OPEN 3#define OPENRAW 4/* * Definition of the driver for autoconf. */int udaprobe(), udaslave(), udaattach(), udadgo(), udaintr();struct uba_ctlr *udaminfo[NUDA];struct uba_device *udadinfo[NRA];struct disklabel udalabel[NRA];u_short udastd[] = { 0772150, 0772550, 0777550, 0 };struct uba_driver udadriver = { udaprobe, udaslave, udaattach, udadgo, udastd, "ra", udadinfo, "uda", udaminfo };/* * More driver definitions, for generic MSCP code. */int udadgram(), udactlrdone(), udaunconf(), udaiodone();int udaonline(), udagotstatus(), udaioerror(), udareplace(), udabb();struct buf udautab[NRA]; /* per drive transfer queue */struct mscp_driver udamscpdriver = { MAXUNIT, NRA, UNITSHIFT, udautab, udalabel, udadinfo, udadgram, udactlrdone, udaunconf, udaiodone, udaonline, udagotstatus, udareplace, udaioerror, udabb, "uda", "ra" };/* * Miscellaneous private variables. */char udasr_bits[] = UDASR_BITS;struct uba_device *udaip[NUDA][MAXUNIT]; /* inverting pointers: ctlr & unit => Unibus device pointer */int udaburst[NUDA] = { 0 }; /* burst size, per UDA50, zero => default; in data space so patchable via adb */struct mscp udaslavereply; /* get unit status response packet, set for udaslave by udaunconf, via udaintr */static struct uba_ctlr *probeum;/* this is a hack---autoconf should pass ctlr info to slave routine; instead, we remember the last ctlr argument to probe */int udawstart, udawatch(); /* watchdog timer *//* * Externals */int wakeup();int hz;/* * Poke at a supposed UDA50 to see if it is there. * This routine duplicates some of the code in udainit() only * because autoconf has not set up the right information yet. * We have to do everything `by hand'. */udaprobe(reg, ctlr, um) caddr_t reg; int ctlr; struct uba_ctlr *um;{ register int br, cvec; register struct uda_softc *sc; register struct udadevice *udaddr; register struct mscp_info *mi; int timeout, tries;#ifdef QBA int s;#endif#ifdef VAX750 /* * The UDA50 wants to share BDPs on 750s, but not on 780s or * 8600s. (730s have no BDPs anyway.) Toward this end, we * here set the `keep bdp' flag in the per-driver information * if this is a 750. (We just need to do it once, but it is * easiest to do it now, for each UDA50.) */ if (cpu == VAX_750) udadriver.ud_keepbdp = 1;#endif probeum = um; /* remember for udaslave() */#ifdef lint br = 0; cvec = br; br = cvec; udaintr(0);#endif /* * Set up the controller-specific generic MSCP driver info. * Note that this should really be done in the (nonexistent) * controller attach routine. */ sc = &uda_softc[ctlr]; mi = &sc->sc_mi; mi->mi_md = &udamscpdriver; mi->mi_ctlr = um->um_ctlr; mi->mi_tab = &um->um_tab; mi->mi_ip = udaip[ctlr]; mi->mi_cmd.mri_size = NCMD; mi->mi_cmd.mri_desc = uda[ctlr].uda_ca.ca_cmddsc; mi->mi_cmd.mri_ring = uda[ctlr].uda_cmd; mi->mi_rsp.mri_size = NRSP; mi->mi_rsp.mri_desc = uda[ctlr].uda_ca.ca_rspdsc; mi->mi_rsp.mri_ring = uda[ctlr].uda_rsp; mi->mi_wtab.av_forw = mi->mi_wtab.av_back = &mi->mi_wtab; /* * More controller specific variables. Again, this should * be in the controller attach routine. */ if (udaburst[ctlr] == 0) udaburst[ctlr] = DEFAULT_BURST; /* * Get an interrupt vector. Note that even if the controller * does not respond, we keep the vector. This is not a serious * problem; but it would be easily fixed if we had a controller * attach routine. Sigh. */ sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); udaddr = (struct udadevice *) reg; /* * Initialise the controller (partially). The UDA50 programmer's * manual states that if initialisation fails, it should be retried * at least once, but after a second failure the port should be * considered `down'; it also mentions that the controller should * initialise within ten seconds. Or so I hear; I have not seen * this manual myself. */#if defined(QBA) && !defined(GENERIC) s = spl6();#endif tries = 0;again: udaddr->udaip = 0; /* start initialisation */ timeout = todr() + 1000; /* timeout in 10 seconds */ while ((udaddr->udasa & UDA_STEP1) == 0) if (todr() > timeout) goto bad; udaddr->udasa = UDA_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | UDA_IE | (sc->sc_ivec >> 2); while ((udaddr->udasa & UDA_STEP2) == 0) if (todr() > timeout) goto bad; /* should have interrupted by now */#ifdef QBA#ifndef GENERIC sc->sc_ipl = br = qbgetpri();#else sc->sc_ipl = br = 0x15;#endif#endif return (sizeof (struct udadevice));bad: if (++tries < 2) goto again;#if defined(QBA) && !defined(GENERIC) splx(s);#endif return (0);}/* * Find a slave. We allow wildcard slave numbers (something autoconf * is not really prepared to deal with); and we need to know the * controller number to talk to the UDA. For the latter, we keep * track of the last controller probed, since a controller probe * immediately precedes all slave probes for that controller. For the * former, we simply put the unit number into ui->ui_slave after we * have found one. * * Note that by the time udaslave is called, the interrupt vector * for the UDA50 has been set up (so that udaunconf() will be called). */udaslave(ui, reg) register struct uba_device *ui; caddr_t reg;{ register struct uba_ctlr *um = probeum; register struct mscp *mp; register struct uda_softc *sc; int next = 0, timeout, tries, i;#ifdef lint i = 0; i = i;#endif /* * Make sure the controller is fully initialised, by waiting * for it if necessary. */ sc = &uda_softc[um->um_ctlr]; if (sc->sc_state == ST_RUN) goto findunit; tries = 0;again: if (udainit(ui->ui_ctlr)) return (0); timeout = todr() + 1000; /* 10 seconds */ while (todr() < timeout) if (sc->sc_state == ST_RUN) /* made it */ goto findunit; if (++tries < 2) goto again; printf("uda%d: controller hung\n", um->um_ctlr); return (0); /* * The controller is all set; go find the unit. Grab an * MSCP packet and send out a Get Unit Status command, with * the `next unit' modifier if we are looking for a generic * unit. We set the `in slave' flag so that udaunconf() * knows to copy the response to `udaslavereply'. */findunit: udaslavereply.mscp_opcode = 0; sc->sc_flags |= SC_INSLAVE; if ((mp = mscp_getcp(&sc->sc_mi, MSCP_DONTWAIT)) == NULL) panic("udaslave"); /* `cannot happen' */ mp->mscp_opcode = M_OP_GETUNITST; if (ui->ui_slave == '?') { mp->mscp_unit = next; mp->mscp_modifier = M_GUM_NEXTUNIT; } else { mp->mscp_unit = ui->ui_slave; mp->mscp_modifier = 0; } *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = ((struct udadevice *) reg)->udaip; /* initiate polling */ mp = &udaslavereply; timeout = todr() + 1000; while (todr() < timeout) if (mp->mscp_opcode) goto gotit; printf("uda%d: no response to Get Unit Status request\n", um->um_ctlr); sc->sc_flags &= ~SC_INSLAVE; return (0);gotit: sc->sc_flags &= ~SC_INSLAVE; /* * Got a slave response. If the unit is there, use it. */ switch (mp->mscp_status & M_ST_MASK) { case M_ST_SUCCESS: /* worked */ case M_ST_AVAILABLE: /* found another drive */ break; /* use it */ case M_ST_OFFLINE: /* * Figure out why it is off line. It may be because
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -