📄 kdb.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. * * @(#)kdb.c 7.10 (Berkeley) 12/16/90 *//* * KDB50/MSCP device driver *//* * TODO * rethink BI software interface * write bad block forwarding code */#include "kra.h" /* XXX */#define DRIVENAMES "kra" /* XXX */#if NKDB > 0/* * CONFIGURATION OPTIONS. The next three defines are tunable -- tune away! * * 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 slave number (and hence number of drives * per controller) we are prepared to handle. */#define NRSPL2 5 /* log2 number of response packets */#define NCMDL2 5 /* log2 number of command packets */#define MAXUNIT 8 /* maximum allowed unit number */#include "sys/param.h"#include "sys/systm.h"#include "sys/malloc.h"#include "sys/map.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/user.h"#include "sys/proc.h"#include "sys/vm.h"#include "sys/dkstat.h"#include "sys/cmap.h"#include "sys/syslog.h"#include "sys/kernel.h"#define NRSP (1 << NRSPL2)#define NCMD (1 << NCMDL2)#include "../include/pte.h"#include "../include/cpu.h"#include "../vax/mscp.h"#include "../vax/mscpvar.h"#include "../include/mtpr.h"#include "bireg.h"#include "kdbreg.h"#include "../uba/ubavar.h"/* * Conversions from kernel virtual to physical and page table addresses. * PHYS works only for kernel text and primary (compile time) data addresses. */#define PHYS(cast, addr) \ ((cast) ((int)(addr) & 0x7fffffff))/* * KDB variables, per controller. */struct kdbinfo { /* software info, per KDB */ struct kdb_regs *ki_kdb; /* KDB registers */ struct kdb_regs *ki_physkdb; /* phys address of KDB registers */ short ki_state; /* KDB50 state; see below */ short ki_flags; /* flags; see below */ int ki_micro; /* microcode revision */ short ki_vec; /* scb vector offset */ short ki_wticks; /* watchdog timer ticks */ /* * KDB PTEs must be contiguous. Some I/O is done on addresses * for which this is true (PTEs in Sysmap and Usrptmap), but * other transfers may have PTEs that are scattered in physical * space. Ki_map maps a physically contiguous PTE space used * for these transfers. */#define KI_MAPSIZ (NCMD + 2) struct map *ki_map; /* resource map */#define KI_PTES 256 struct pte ki_pte[KI_PTES]; /* contiguous PTE space */ long ki_ptephys; /* phys address of &ki_pte[0] */ struct mscp_info ki_mi; /* MSCP info (per mscpvar.h) */ struct buf ki_tab; /* controller queue */ /* stuff read and written by hardware */ struct kdbca ki_ca; /* communications area */ struct mscp ki_rsp[NRSP]; /* response packets */ struct mscp ki_cmd[NCMD]; /* command packets */} kdbinfo[NKDB];#define ki_ctlr ki_mi.mi_ctlr/* * 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 KDB_ALIVE 0x01 /* this KDB50 exists */#define KDB_GRIPED 0x04 /* griped about cmd ring too small */#define KDB_INSLAVE 0x08 /* inside kdbslave() */#define KDB_DOWAKE 0x10 /* wakeup when ctlr init done */struct kdbstats kdbstats; /* statistics *//* * Device to unit number and partition: */#define UNITSHIFT 3#define UNITMASK 7#define kdbunit(dev) (minor(dev) >> UNITSHIFT)#define kdbpart(dev) (minor(dev) & UNITMASK)/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE *//* THESE SHOULD BE SHARED WITH uda.c (but not yet) */struct size { daddr_t nblocks; daddr_t blkoff;} kra81_sizes[8] = {#ifdef MARYLAND 67832, 0, /* A=cyl 0 thru 94 + 2 sectors */ 67828, 67832, /* B=cyl 95 thru 189 - 2 sectors */ -1, 0, /* C=cyl 0 thru 1247 */ -1, 135660, /* D=cyl 190 thru 1247 */ 449466, 49324, /* E xxx */ 64260, 498790, /* F xxx */ 328022, 563050, /* G xxx */ 0, 0,#else 15884, 0, /* a */ 33440, 15884, /* b */ -1, 0, /* c */ -1, 49324, /* d */ 449466, 49324, /* e */ 64260, 498790, /* f */ 328022, 563050, /* g */ 0, 0,#endif}, kra80_sizes[8] = { 15884, 0, /* A=blk 0 thru 15883 */ 33440, 15884, /* B=blk 15884 thru 49323 */ -1, 0, /* C=blk 0 thru end */ 0, 0, 0, 0, 0, 0, 82080, 49324, /* G=blk 49324 thru 131403 */ -1, 131404, /* H=blk 131404 thru end */}, kra60_sizes[8] = { 15884, 0, /* A=blk 0 thru 15883 */ 33440, 15884, /* B=blk 15884 thru 49323 */ -1, 0, /* C=blk 0 thru end */ -1, 49324, /* D=blk 49324 thru end */ 0, 0, 0, 0, 82080, 49324, /* G=blk 49324 thru 131403 */ -1, 131404, /* H=blk 131404 thru end */};/* END OF STUFF WHICH SHOULD BE READ IN PER DISK *//* * Drive type index decoding table. `ut_name' is null iff the * type is not known. */struct kdbtypes { char *ut_name; /* drive type name */ struct size *ut_sizes; /* partition tables */} kdbtypes[] = { NULL, NULL, "ra80", kra80_sizes, /* 1 = ra80 */ NULL, NULL, NULL, NULL, "ra60", kra60_sizes, /* 4 = ra60 */ "ra81", kra81_sizes, /* 5 = ra81 */};#define NTYPES 6/* * Definition of the driver for autoconf and generic MSCP code. * SOME OF THIS IS BOGUS (must fix config) */#ifdef notdef /* not when driver is for kra disks *//* * Some of these variables (per-drive stuff) are shared * with the UDA50 code (why not, they are the same drives). * N.B.: kdbdinfo must not be shared. */#define kdbutab udautab /* shared */#define kdbslavereply udaslavereply /* shared */#endifint kdbprobe(); /* XXX */int kdbslave(), kdbattach();int kdbdgram(), kdbctlrdone(), kdbunconf(), kdbiodone();int kdbonline(), kdbgotstatus(), kdbioerror();struct uba_device *kdbdinfo[NKRA]; /* uba_device indeed! */struct buf kdbutab[NKRA]; /* per drive transfer queue */u_short kdbstd[] = { 0 }; /* XXX */struct uba_driver kdbdriver = /* XXX */ { kdbprobe, kdbslave, kdbattach, 0, kdbstd, DRIVENAMES, kdbdinfo, "kdb" };struct mscp_driver kdbmscpdriver = { MAXUNIT, NKRA, UNITSHIFT, kdbutab, (struct disklabel *)0, kdbdinfo, kdbdgram, kdbctlrdone, kdbunconf, kdbiodone, kdbonline, kdbgotstatus, NULL, kdbioerror, NULL, "kdb", DRIVENAMES };/* * Miscellaneous private variables. */char kdbsr_bits[] = KDBSR_BITS;struct uba_device *kdbip[NKDB][MAXUNIT]; /* inverting pointers: ctlr & unit => `Unibus' device pointer */daddr_t ra_dsize[NKRA]; /* drive sizes, from on line end packets */struct mscp kdbslavereply; /* get unit status response packet, set for kdbslave by kdbunconf, via kdbintr */int kdbwstart, kdbwatch(); /* watchdog timer */int wakeup();/* * If kdbprobe is called, return 0 to keep Unibus code from attempting * to use this device. XXX rethink *//* ARGSUSED */kdbprobe(reg, ctlr) caddr_t reg; int ctlr;{ return (0);}/* * Configure in a KDB50 controller. */kdbconfig(kdbnum, va, pa, vec) int kdbnum; struct biiregs *va, *pa; int vec;{ register struct kdbinfo *ki;#define mi (&ki->ki_mi)#ifdef lint extern int (*kdbint0[])(); (*kdbint0[0])(0); /* this is a config botch */ kdbintr(0);#endif /* * Set up local KDB status. */ ki = &kdbinfo[kdbnum]; ki->ki_kdb = (struct kdb_regs *)va; ki->ki_physkdb = (struct kdb_regs *)pa; ki->ki_vec = vec; ki->ki_map = (struct map *)malloc((u_long)(KI_MAPSIZ * sizeof(struct map)), M_DEVBUF, M_NOWAIT); if (ki->ki_map == NULL) { printf("kdb%d: cannot get memory for ptes\n", kdbnum); return; } ki->ki_ptephys = PHYS(long, ki->ki_pte); /* kvtophys(ki->ki_pte) */ ki->ki_flags = KDB_ALIVE; /* THE FOLLOWING IS ONLY NEEDED TO CIRCUMVENT A BUG IN rminit */ bzero((caddr_t)ki->ki_map, KI_MAPSIZ * sizeof(struct map)); rminit(ki->ki_map, (long)KI_PTES, (long)1, "kdb", KI_MAPSIZ); /* * Set up the generic MSCP structures. */ mi->mi_md = &kdbmscpdriver; mi->mi_ctlr = kdbnum; /* also sets ki->ki_ctlr */ mi->mi_tab = &ki->ki_tab; mi->mi_ip = kdbip[kdbnum]; mi->mi_cmd.mri_size = NCMD; mi->mi_cmd.mri_desc = ki->ki_ca.ca_cmddsc; mi->mi_cmd.mri_ring = ki->ki_cmd; mi->mi_rsp.mri_size = NRSP; mi->mi_rsp.mri_desc = ki->ki_ca.ca_rspdsc; mi->mi_rsp.mri_ring = ki->ki_rsp; mi->mi_wtab.av_forw = mi->mi_wtab.av_back = &mi->mi_wtab;#undef mi}/* * Find a slave. * Note that by the time kdbslave is called, the interrupt vector * for the KDB50 has been set up (so that kdbunconf() will be called). */kdbslave(ui) register struct uba_device *ui;{ register struct kdbinfo *ki; register struct mscp *mp; int next = 0, type, timeout, tries, i;#ifdef lint i = 0; i = i;#endif /* * Make sure the controller is fully initialised, by waiting * for it if necessary. */ ki = &kdbinfo[ui->ui_ctlr]; if (ki->ki_state == ST_RUN) goto findunit; tries = 0;again: if (kdbinit(ki)) return (0); timeout = todr() + 1000; /* 10 seconds */ while (todr() < timeout) if (ki->ki_state == ST_RUN) /* made it */ goto findunit; if (++tries < 2) goto again; printf("kdb%d: controller hung\n", ki->ki_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 kdbunconf() * knows to copy the response to `kdbslavereply'. */findunit: kdbslavereply.mscp_opcode = 0; ki->ki_flags |= KDB_INSLAVE; if ((mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT)) == NULL) panic("kdbslave"); /* `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 = ki->ki_kdb->kdb_ip; /* initiate polling */ mp = &kdbslavereply; timeout = todr() + 1000; while (todr() < timeout) if (mp->mscp_opcode) goto gotit; printf("kdb%d: no response to Get Unit Status request\n", ki->ki_ctlr); ki->ki_flags &= ~KDB_INSLAVE; return (0);gotit: ki->ki_flags &= ~KDB_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 * it is nonexistent, or because it is spun down, or * for some other reason. */ switch (mp->mscp_status & ~M_ST_MASK) { case M_OFFLINE_UNKNOWN: /* * No such drive, and there are none with * higher unit numbers either, if we are * using M_GUM_NEXTUNIT. */ return (0); case M_OFFLINE_UNMOUNTED: /* * The drive is not spun up. Use it anyway. * * N.B.: this seems to be a common occurrance * after a power failure. The first attempt * to bring it on line seems to spin it up * (and thus takes several minutes). Perhaps * we should note here that the on-line may * take longer than usual. */ break; default: /* * In service, or something else equally unusable. */ printf("kdb%d: unit %d off line:", ki->ki_ctlr, mp->mscp_unit); mscp_printevent(mp); goto try_another; } break; default: printf("kdb%d: unable to get unit status:", ki->ki_ctlr); mscp_printevent(mp); return (0); } /* * Does this ever happen? What (if anything) does it mean? */ if (mp->mscp_unit < next) { printf("kdb%d: unit %d, next %d\n", ki->ki_ctlr, mp->mscp_unit, next); return (0); } if (mp->mscp_unit >= MAXUNIT) { printf("kdb%d: cannot handle unit number %d (max is %d)\n", ki->ki_ctlr, mp->mscp_unit, MAXUNIT - 1); return (0); } /* * See if we already handle this drive. * (Only likely if ui->ui_slave=='?'.) */ if (kdbip[ki->ki_ctlr][mp->mscp_unit] != NULL) goto try_another; /* * Make sure we know about this kind of drive. * Others say we should treat unknowns as RA81s; I am * not sure this is safe. */ type = mp->mscp_guse.guse_drivetype; if (type >= NTYPES || kdbtypes[type].ut_name == 0) { register long id = mp->mscp_guse.guse_mediaid; printf("kdb%d: unit %d: media ID `", ki->ki_ctlr, mp->mscp_unit); printf("%c%c %c%c%c%d", MSCP_MID_CHAR(4, id), MSCP_MID_CHAR(3, id), MSCP_MID_CHAR(2, id), MSCP_MID_CHAR(1, id), MSCP_MID_CHAR(0, id), MSCP_MID_NUM(id)); printf("' is of unknown type %d; ignored\n", type);try_another: if (ui->ui_slave != '?') return (0); next = mp->mscp_unit + 1; goto findunit; } /* * Voila! */ ui->ui_type = type; ui->ui_flags = 0; /* not on line, nor anything else */ ui->ui_slave = mp->mscp_unit; return (1);}/* * Attach a found slave. Make sure the watchdog timer is running. * If this disk is being profiled, fill in the `wpms' value (used by * what?). Set up the inverting pointer, and attempt to bring the * drive on line. */kdbattach(ui) register struct uba_device *ui;{ if (kdbwstart == 0) { timeout(kdbwatch, (caddr_t)0, hz); kdbwstart++; } if (ui->ui_dk >= 0) dk_wpms[ui->ui_dk] = (60 * 31 * 256); /* approx */ kdbip[ui->ui_ctlr][ui->ui_slave] = ui; (void) kdb_bringonline(ui, 1); /* should we get its status too? */}/* * Initialise a KDB50. Return true iff something goes wrong. */kdbinit(ki) register struct kdbinfo *ki;{ register struct kdb_regs *ka = ki->ki_kdb; int timo; /* * While we are thinking about it, reset the next command * and response indicies. */ ki->ki_mi.mi_cmd.mri_next = 0; ki->ki_mi.mi_rsp.mri_next = 0; /* * Start up the hardware initialisation sequence. */#define STEP0MASK (KDB_ERR | KDB_STEP4 | KDB_STEP3 | KDB_STEP2 | KDB_STEP1) ki->ki_state = ST_IDLE; /* in case init fails */ bi_reset(&ka->kdb_bi); /* reset bi node (but not the BI itself) */ timo = todr() + 1000; while ((ka->kdb_sa & STEP0MASK) == 0) { if (todr() > timo) { printf("kdb%d: timeout during init\n", ki->ki_ctlr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -