/* * 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 are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#)kdb.c 7.6 (Berkeley) 07/09/88 */ /* * 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 "param.h" #include "systm.h" #include "malloc.h" #include "map.h" #include "buf.h" #include "conf.h" #include "dir.h" #include "user.h" #include "proc.h" #include "vm.h" #include "dkstat.h" #include "cmap.h" #include "syslog.h" #include "kernel.h" #define NRSP (1 << NRSPL2) #define NCMD (1 << NCMDL2) #include "../vax/pte.h" #include "../vax/cpu.h" #include "../vax/mscp.h" #include "../vax/mscpvar.h" #include "../vax/mtpr.h" #include "bireg.h" #include "kdbreg.h" #include "../vaxuba/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 */ #endif int 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 `mspw' 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_mspw[ui->ui_dk] = 1.0 / (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); return (-1); } } if ((ka->kdb_sa & STEP0MASK) != KDB_STEP1) { printf("kdb%d: init failed, sa=%b\n", ki->ki_ctlr, ka->kdb_sa, kdbsr_bits); return (-1); } /* * Success! Record new state, and start step 1 initialisation. * The rest is done in the interrupt handler. */ ki->ki_state = ST_STEP1; ka->kdb_bi.bi_intrdes = 1 << mastercpu; #ifdef unneeded /* is it? */ ka->kdb_bi.bi_csr = (ka->kdb_bi.bi_csr&~BICSR_ARB_MASK)|BICSR_ARB_???; #endif ka->kdb_bi.bi_bcicsr |= BCI_STOPEN | BCI_IDENTEN | BCI_UINTEN | BCI_INTEN; /* I THINK THIS IS WRONG */ /* Mach uses 0x601d0, which includes IPL16, but 1d0 is IPL17, nexzvec...? */ ka->kdb_bi.bi_eintrcsr = BIEIC_IPL15 | ki->ki_vec; /* ??? */ /* END I THINK WRONG */ ka->kdb_bi.bi_uintrcsr = ki->ki_vec; ka->kdb_sw = KDB_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | KDB_IE | (ki->ki_vec >> 2); return (0); } /* * Open a drive. */ /*ARGSUSED*/ kdbopen(dev, flag) dev_t dev; int flag; { register int unit; register struct uba_device *ui; register struct kdbinfo *ki; int s; /* * Make sure this is a reasonable open request. */ unit = kdbunit(dev); if (unit >= NKRA || (ui = kdbdinfo[unit]) == 0 || ui->ui_alive == 0) return (ENXIO); /* * Make sure the controller is running, by (re)initialising it if * necessary. */ ki = &kdbinfo[ui->ui_ctlr]; s = spl5(); if (ki->ki_state != ST_RUN) { if (ki->ki_state == ST_IDLE && kdbinit(ki)) { splx(s); return (EIO); } /* * In case it does not come up, make sure we will be * restarted in 10 seconds. This corresponds to the * 10 second timeouts in kdbprobe() and kdbslave(). */ ki->ki_flags |= KDB_DOWAKE; timeout(wakeup, (caddr_t)&ki->ki_flags, 10 * hz); sleep((caddr_t)&ki->ki_flags, PRIBIO); if (ki->ki_state != ST_RUN) { splx(s); printf("kdb%d: controller hung\n", ui->ui_ctlr); return (EIO); } untimeout(wakeup, (caddr_t)&ki->ki_flags); } if ((ui->ui_flags & UNIT_ONLINE) == 0) { /* * Bring the drive on line so we can find out how * big it is. If it is not spun up, it will not * come on line; this cannot really be considered * an `error condition'. */ if (kdb_bringonline(ui, 0)) { splx(s); printf("%s%d: drive will not come on line\n", kdbdriver.ud_dname, unit); return (EIO); } } splx(s); return (0); } /* * Bring a drive on line. In case it fails to respond, we set * a timeout on it. The `nosleep' parameter should be set if * we are to spin-wait; otherwise this must be called at spl5(). */ kdb_bringonline(ui, nosleep) register struct uba_device *ui; int nosleep; { register struct kdbinfo *ki = &kdbinfo[ui->ui_ctlr]; register struct mscp *mp; int i; if (nosleep) { mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT); if (mp == NULL) return (-1); } else mp = mscp_getcp(&ki->ki_mi, MSCP_WAIT); mp->mscp_opcode = M_OP_ONLINE; mp->mscp_unit = ui->ui_slave; mp->mscp_cmdref = (long)&ui->ui_flags; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = ki->ki_kdb->kdb_ip; if (nosleep) { i = todr() + 1000; while ((ui->ui_flags & UNIT_ONLINE) == 0) if (todr() > i) return (-1); } else { timeout(wakeup, (caddr_t)&ui->ui_flags, 10 * hz); sleep((caddr_t)&ui->ui_flags, PRIBIO); if ((ui->ui_flags & UNIT_ONLINE) == 0) return (-1); untimeout(wakeup, (caddr_t)&ui->ui_flags); } return (0); /* made it */ } /* * Queue a transfer request, and if possible, hand it to the controller. * * This routine is broken into two so that the internal version * kdbstrat1() can be called by the (nonexistent, as yet) bad block * revectoring routine. */ kdbstrategy(bp) register struct buf *bp; { register int unit; register struct uba_device *ui; register struct size *st; daddr_t sz, maxsz; /* * Make sure this is a reasonable drive to use. */ if ((unit = kdbunit(bp->b_dev)) >= NKRA || (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0) { bp->b_error = ENXIO; bp->b_flags |= B_ERROR; biodone(bp); return; } /* * Determine the size of the transfer, and make sure it is * within the boundaries of the drive. */ sz = (bp->b_bcount + 511) >> 9; st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)]; if ((maxsz = st->nblocks) < 0) maxsz = ra_dsize[unit] - st->blkoff; if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz || st->blkoff >= ra_dsize[unit]) { /* if exactly at end of disk, return an EOF */ if (bp->b_blkno == maxsz) bp->b_resid = bp->b_bcount; else { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; } biodone(bp); return; } kdbstrat1(bp); } /* * Work routine for kdbstrategy. */ kdbstrat1(bp) register struct buf *bp; { register int unit = kdbunit(bp->b_dev); register struct buf *dp; register struct kdbinfo *ki; struct uba_device *ui; int s; /* * Append the buffer to the drive queue, and if it is not * already there, the drive to the controller queue. (However, * if the drive queue is marked to be requeued, we must be * awaiting an on line or get unit status command; in this * case, leave it off the controller queue.) */ ui = kdbdinfo[unit]; ki = &kdbinfo[ui->ui_ctlr]; dp = &kdbutab[unit]; s = spl5(); APPEND(bp, dp, av_forw); if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) { APPEND(dp, &ki->ki_tab, b_forw); dp->b_active++; } /* * Start activity on the controller. */ kdbstart(ki); splx(s); } /* * Find the physical address of some contiguous PTEs that map the * transfer described in `bp', creating them (by copying) if * necessary. Store the physical base address of the map through * mapbase, and the page offset through offset, and any resource * information in *info (or 0 if none). * * If we cannot allocate space, return a nonzero status. */ int kdbmap(ki, bp, mapbase, offset, info) struct kdbinfo *ki; register struct buf *bp; long *mapbase, *offset; int *info; { register struct pte *spte, *dpte; register struct proc *rp; register int i, a, o; u_int v; int npf; o = (int)bp->b_un.b_addr & PGOFSET; /* handle contiguous cases */ if ((bp->b_flags & B_PHYS) == 0) { spte = kvtopte(bp->b_un.b_addr); kdbstats.ks_sys++; *mapbase = PHYS(long, spte); *offset = o; *info = 0; return (0); } if (bp->b_flags & B_PAGET) { spte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; if (spte->pg_v == 0) panic("kdbmap"); kdbstats.ks_paget++; *mapbase = PHYS(long, spte); *offset = o; *info = 0; return (0); } /* potentially discontiguous or invalid ptes */ v = btop(bp->b_un.b_addr); rp = bp->b_flags & B_DIRTY ? &proc[2] : bp->b_proc; if (bp->b_flags & B_UAREA) spte = &rp->p_addr[v]; else spte = vtopte(rp, v); npf = btoc(bp->b_bcount + o); #ifdef notdef /* * The current implementation of the VM system requires * that all of these be done with a copy. Even if the * PTEs could be used now, they may be snatched out from * under us later. It would be nice if we could stop that.... */ /* check for invalid */ /* CONSIDER CHANGING VM TO VALIDATE PAGES EARLIER */ for (dpte = spte, i = npf; --i >= 0; dpte++) if (dpte->pg_v == 0) goto copy1; /* * Check for discontiguous physical pte addresses. It is * not necessary to check each pte, since they come in clumps * of pages. */ i = howmany(npf + (((int)spte & PGOFSET) / sizeof (*spte)), NPTEPG); /* often i==1, and we can avoid work */ if (--i > 0) { dpte = kvtopte(spte); a = dpte->pg_pfnum; while (--i >= 0) if ((++dpte)->pg_pfnum != ++a) goto copy2; } /* made it */ kdbstats.ks_contig++; *mapbase = kvtophys(spte); *offset = o; *info = 0; return (0); copy1: kdbstats.ks_inval++; /* temp */ copy2: #endif /* notdef */ kdbstats.ks_copies++; i = npf + 1; if ((a = rmalloc(ki->ki_map, (long)i)) == 0) { kdbstats.ks_mapwait++; return (-1); } *info = (i << 16) | a; a--; /* if offset > PGOFSET, btop(offset) indexes mapbase */ *mapbase = ki->ki_ptephys; *offset = (a << PGSHIFT) | o; dpte = &ki->ki_pte[a]; while (--i > 0) *(int *)dpte++ = PG_V | *(int *)spte++; *(int *)dpte = 0; return (0); } #define KDBFREE(ki, info) if (info) \ rmfree((ki)->ki_map, (long)((info) >> 16), (long)((info) & 0xffff)) /* * Start up whatever transfers we can find. * Note that kdbstart() must be called at spl5(). */ kdbstart(ki) register struct kdbinfo *ki; { register struct buf *bp, *dp; register struct mscp *mp; register struct uba_device *ui; long mapbase, offset; int info, ncmd = 0; /* * If it is not running, try (again and again...) to initialise * it. If it is currently initialising just ignore it for now. */ if (ki->ki_state != ST_RUN) { if (ki->ki_state == ST_IDLE && kdbinit(ki)) printf("kdb%d: still hung\n", ki->ki_ctlr); return; } loop: /* if insufficient credit, avoid overhead */ if (ki->ki_mi.mi_credits <= MSCP_MINCREDITS) goto out; /* * Service the drive at the head of the queue. It may not * need anything; eventually this will finish up the close * protocol, but that is yet to be implemented here. */ if ((dp = ki->ki_tab.b_actf) == NULL) goto out; if ((bp = dp->b_actf) == NULL) { dp->b_active = 0; ki->ki_tab.b_actf = dp->b_forw; goto loop; } if (ki->ki_kdb->kdb_sa & KDB_ERR) { /* ctlr fatal error */ kdbsaerror(ki); goto out; } /* find or create maps for this transfer */ if (kdbmap(ki, bp, &mapbase, &offset, &info)) goto out; /* effectively, resource wait */ /* * Get an MSCP packet, then figure out what to do. If * we cannot get a command packet, the command ring may * be too small: We should have at least as many command * packets as credits, for best performance. */ if ((mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT)) == NULL) { if (ki->ki_mi.mi_credits > MSCP_MINCREDITS && (ki->ki_flags & KDB_GRIPED) == 0) { log(LOG_NOTICE, "kdb%d: command ring too small\n", ki->ki_ctlr); ki->ki_flags |= KDB_GRIPED;/* complain only once */ } KDBFREE(ki, info); goto out; } /* * Bring the drive on line if it is not already. Get its status * if we do not already have it. Otherwise just start the transfer. */ ui = kdbdinfo[kdbunit(bp->b_dev)]; if ((ui->ui_flags & UNIT_ONLINE) == 0) { mp->mscp_opcode = M_OP_ONLINE; goto common; } if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) { mp->mscp_opcode = M_OP_GETUNITST; common: if (ui->ui_flags & UNIT_REQUEUE) panic("kdbstart"); /* * Take the drive off the controller queue. When the * command finishes, make sure the drive is requeued. * Give up any mapping (not needed now). This last is * not efficient, but is rare. */ KDBFREE(ki, info); ki->ki_tab.b_actf = dp->b_forw; dp->b_active = 0; ui->ui_flags |= UNIT_REQUEUE; mp->mscp_unit = ui->ui_slave; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; ncmd++; goto loop; } mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE; mp->mscp_unit = ui->ui_slave; mp->mscp_seq.seq_lbn = bp->b_blkno + kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)].blkoff; mp->mscp_seq.seq_bytecount = bp->b_bcount; mp->mscp_seq.seq_buffer = offset | KDB_MAP; mp->mscp_seq.seq_mapbase = mapbase; /* profile the drive */ if (ui->ui_dk >= 0) { dk_busy |= 1 << ui->ui_dk; dk_xfer[ui->ui_dk]++; dk_wds[ui->ui_dk] += bp->b_bcount >> 6; } /* * Fill in the rest of the MSCP packet and move the buffer to the * I/O wait queue. */ mscp_go(&ki->ki_mi, mp, info); ncmd++; /* note the transfer */ ki->ki_tab.b_active++; /* another one going */ goto loop; out: if (ncmd >= KS_MAXC) ncmd = KS_MAXC - 1; kdbstats.ks_cmd[ncmd]++; if (ncmd) /* start some transfers */ ncmd = ki->ki_kdb->kdb_ip; } /* ARGSUSED */ kdbiodone(mi, bp, info) struct mscp_info *mi; struct buf *bp; int info; { register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr]; KDBFREE(ki, info); biodone(bp); ki->ki_tab.b_active--; /* another one done */ } /* * The error bit was set in the controller status register. Gripe, * reset the controller, requeue pending transfers. */ kdbsaerror(ki) register struct kdbinfo *ki; { printf("kdb%d: controller error, sa=%b\n", ki->ki_ctlr, ki->ki_kdb->kdb_sa, kdbsr_bits); mscp_requeue(&ki->ki_mi); (void) kdbinit(ki); } /* * Interrupt routine. Depending on the state of the controller, * continue initialisation, or acknowledge command and response * interrupts, and process responses. */ kdbintr(ctlr) int ctlr; { register struct kdbinfo *ki = &kdbinfo[ctlr]; register struct kdb_regs *kdbaddr = ki->ki_kdb; register struct mscp *mp; register int i; ki->ki_wticks = 0; /* reset interrupt watchdog */ /* * Combinations during steps 1, 2, and 3: STEPnMASK * corresponds to which bits should be tested; * STEPnGOOD corresponds to the pattern that should * appear after the interrupt from STEPn initialisation. * All steps test the bits in ALLSTEPS. */ #define ALLSTEPS (KDB_ERR|KDB_STEP4|KDB_STEP3|KDB_STEP2|KDB_STEP1) #define STEP1MASK (ALLSTEPS | KDB_IE | KDB_NCNRMASK) #define STEP1GOOD (KDB_STEP2 | KDB_IE | (NCMDL2 << 3) | NRSPL2) #define STEP2MASK (ALLSTEPS | KDB_IE | KDB_IVECMASK) #define STEP2GOOD (KDB_STEP3 | KDB_IE | (ki->ki_vec >> 2)) #define STEP3MASK ALLSTEPS #define STEP3GOOD KDB_STEP4 switch (ki->ki_state) { case ST_IDLE: /* * Ignore unsolicited interrupts. */ log(LOG_WARNING, "kdb%d: stray intr\n", ctlr); return; case ST_STEP1: /* * Begin step two initialisation. */ if ((kdbaddr->kdb_sa & STEP1MASK) != STEP1GOOD) { i = 1; initfailed: printf("kdb%d: init step %d failed, sa=%b\n", ctlr, i, kdbaddr->kdb_sa, kdbsr_bits); ki->ki_state = ST_IDLE; if (ki->ki_flags & KDB_DOWAKE) { ki->ki_flags &= ~KDB_DOWAKE; wakeup((caddr_t)&ki->ki_flags); } return; } kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]); ki->ki_state = ST_STEP2; return; case ST_STEP2: /* * Begin step 3 initialisation. */ if ((kdbaddr->kdb_sa & STEP2MASK) != STEP2GOOD) { i = 2; goto initfailed; } kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]) >> 16; ki->ki_state = ST_STEP3; return; case ST_STEP3: /* * Set controller characteristics (finish initialisation). */ if ((kdbaddr->kdb_sa & STEP3MASK) != STEP3GOOD) { i = 3; goto initfailed; } i = kdbaddr->kdb_sa & 0xff; if (i != ki->ki_micro) { ki->ki_micro = i; printf("kdb%d: version %d model %d\n", ctlr, i & 0xf, i >> 4); } kdbaddr->kdb_sw = KDB_GO; /* initialise hardware data structures */ for (i = 0, mp = ki->ki_rsp; i < NRSP; i++, mp++) { ki->ki_ca.ca_rspdsc[i] = MSCP_OWN | MSCP_INT | PHYS(long, &ki->ki_rsp[i].mscp_cmdref); mp->mscp_addr = &ki->ki_ca.ca_rspdsc[i]; mp->mscp_msglen = MSCP_MSGLEN; } for (i = 0, mp = ki->ki_cmd; i < NCMD; i++, mp++) { ki->ki_ca.ca_cmddsc[i] = MSCP_INT | PHYS(long, &ki->ki_cmd[i].mscp_cmdref); mp->mscp_addr = &ki->ki_ca.ca_cmddsc[i]; mp->mscp_msglen = MSCP_MSGLEN; } /* * Before we can get a command packet, we need some * credits. Fake some up to keep mscp_getcp() happy, * get a packet, and cancel all credits (the right * number should come back in the response to the * SCC packet). */ ki->ki_mi.mi_credits = MSCP_MINCREDITS + 1; mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT); if (mp == NULL) /* `cannot happen' */ panic("kdbintr"); ki->ki_mi.mi_credits = 0; mp->mscp_opcode = M_OP_SETCTLRC; mp->mscp_unit = 0; mp->mscp_sccc.sccc_ctlrflags = M_CF_ATTN | M_CF_MISC | M_CF_THIS; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = kdbaddr->kdb_ip; ki->ki_state = ST_SETCHAR; return; case ST_SETCHAR: case ST_RUN: /* * Handle Set Ctlr Characteristics responses and operational * responses (via mscp_dorsp). */ break; default: log(LOG_ERR, "kdb%d: driver bug, state %d\n", ctlr, ki->ki_state); return; } if (kdbaddr->kdb_sa & KDB_ERR) {/* ctlr fatal error */ kdbsaerror(ki); return; } /* * Handle buffer purge requests. * KDB DOES NOT HAVE BDPs */ if (ki->ki_ca.ca_bdp) { printf("kdb%d: purge bdp %d\n", ctlr, ki->ki_ca.ca_bdp); panic("kdb purge"); } /* * Check for response and command ring transitions. */ if (ki->ki_ca.ca_rspint) { ki->ki_ca.ca_rspint = 0; mscp_dorsp(&ki->ki_mi); } if (ki->ki_ca.ca_cmdint) { ki->ki_ca.ca_cmdint = 0; MSCP_DOCMD(&ki->ki_mi); } if (ki->ki_tab.b_actf != NULL) kdbstart(ki); } /* * Handle an error datagram. All we do now is decode it. */ kdbdgram(mi, mp) struct mscp_info *mi; struct mscp *mp; { mscp_decodeerror(mi->mi_md->md_mname, mi->mi_ctlr, mp); } /* * The Set Controller Characteristics command finished. * Record the new state of the controller. */ kdbctlrdone(mi, mp) struct mscp_info *mi; struct mscp *mp; { register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr]; if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) ki->ki_state = ST_RUN; else { printf("kdb%d: SETCTLRC failed, status 0x%x\n", ki->ki_ctlr, mp->mscp_status); ki->ki_state = ST_IDLE; } if (ki->ki_flags & KDB_DOWAKE) { ki->ki_flags &= ~KDB_DOWAKE; wakeup((caddr_t)&ki->ki_flags); } } /* * Received a response from an as-yet unconfigured drive. Configure it * in, if possible. */ kdbunconf(mi, mp) struct mscp_info *mi; register struct mscp *mp; { /* * If it is a slave response, copy it to kdbslavereply for * kdbslave() to look at. */ if (mp->mscp_opcode == (M_OP_GETUNITST | M_OP_END) && (kdbinfo[mi->mi_ctlr].ki_flags & KDB_INSLAVE) != 0) { kdbslavereply = *mp; return (MSCP_DONE); } /* * Otherwise, it had better be an available attention response. */ if (mp->mscp_opcode != M_OP_AVAILATTN) return (MSCP_FAILED); /* do what autoconf does */ return (MSCP_FAILED); /* not yet */ } /* * A drive came on line. Check its type and size. Return DONE if * we think the drive is truly on line. In any case, awaken anyone * sleeping on the drive on-line-ness. */ kdbonline(ui, mp) register struct uba_device *ui; struct mscp *mp; { register int type; wakeup((caddr_t)&ui->ui_flags); if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("kdb%d: attempt to bring %s%d on line failed:", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit); mscp_printevent(mp); return (MSCP_FAILED); } type = mp->mscp_onle.onle_drivetype; if (type >= NTYPES || kdbtypes[type].ut_name == 0) { printf("kdb%d: %s%d: unknown type %d\n", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit, type); return (MSCP_FAILED); } /* * Note any change of types. Not sure if we should do * something special about them, or if so, what.... */ if (type != ui->ui_type) { printf("%s%d: changed types! was %s\n", kdbdriver.ud_dname, ui->ui_unit, kdbtypes[ui->ui_type].ut_name); ui->ui_type = type; } ra_dsize[ui->ui_unit] = (daddr_t) mp->mscp_onle.onle_unitsize; printf("%s%d: %s, size = %d sectors\n", kdbdriver.ud_dname, ui->ui_unit, kdbtypes[type].ut_name, ra_dsize[ui->ui_unit]); return (MSCP_DONE); } /* * We got some (configured) unit's status. Return DONE if it succeeded. */ kdbgotstatus(ui, mp) register struct uba_device *ui; register struct mscp *mp; { if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("kdb%d: attempt to get status for %s%d failed:", ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit); mscp_printevent(mp); return (MSCP_FAILED); } /* need to record later for bad block forwarding - for now, print */ printf("\ %s%d: unit %d, nspt %d, group %d, ngpc %d, rctsize %d, nrpt %d, nrct %d\n", kdbdriver.ud_dname, ui->ui_unit, mp->mscp_unit, mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group, mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize, mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct); return (MSCP_DONE); } /* * A transfer failed. We get a chance to fix or restart it. * Need to write the bad block forwaring code first.... */ /*ARGSUSED*/ kdbioerror(ui, mp, bp) register struct uba_device *ui; register struct mscp *mp; struct buf *bp; { if (mp->mscp_flags & M_EF_BBLKR) { /* * A bad block report. Eventually we will * restart this transfer, but for now, just * log it and give up. */ log(LOG_ERR, "%s%d: bad block report: %d%s\n", kdbdriver.ud_dname, ui->ui_unit, mp->mscp_seq.seq_lbn, mp->mscp_flags & M_EF_BBLKU ? " + others" : ""); } else { /* * What the heck IS a `serious exception' anyway? */ if (mp->mscp_flags & M_EF_SEREX) log(LOG_ERR, "%s%d: serious exception reported\n", kdbdriver.ud_dname, ui->ui_unit); } return (MSCP_FAILED); } #ifdef notyet /* * I/O controls. Not yet! */ kdbioctl(dev, cmd, flag, data) dev_t dev; int cmd, flag; caddr_t data; { int error = 0; register int unit = kdbunit(dev); if (unit >= NKRA || uddinfo[unit] == NULL) return (ENXIO); switch (cmd) { case KDBIOCREPLACE: /* * Initiate bad block replacement for the given LBN. * (Should we allow modifiers?) */ error = EOPNOTSUPP; break; case KDBIOCGMICRO: /* * Return the microcode revision for the KDB50 running * this drive. */ *(int *)data = kdbinfo[kdbdinfo[unit]->ui_ctlr].ki_micro; break; case KDBIOCGSIZE: /* * Return the size (in 512 byte blocks) of this * disk drive. */ *(daddr_t *)data = ra_dsize[unit]; break; default: error = EINVAL; break; } return (error); } #endif #ifdef notyet /* * Reset a KDB50 (self test and all). * What if it fails? */ kdbreset(ki) register struct kdbinfo *ki; { printf("reset kdb%d", ki->ki_ctlr); bi_selftest(&ki->ki_kdb.kdb_bi); ki->ki_state = ST_IDLE; rminit(ki->ki_map, (long)KI_PTES, (long)1, "kdb", KI_MAPSIZ); mscp_requeue(&ki->ki_mi); if (kdbinit(ctlr)) printf(" (hung)"); printf("\n"); } #endif /* * Watchdog timer: If the controller is active, and no interrupts * have occurred for 30 seconds, assume it has gone away. */ kdbwatch() { register struct kdbinfo *ki; register int i; timeout(kdbwatch, (caddr_t)0, hz); /* every second */ for (i = 0, ki = kdbinfo; i < NKDB; i++, ki++) { if ((ki->ki_flags & KDB_ALIVE) == 0) continue; if (ki->ki_state == ST_IDLE) continue; if (ki->ki_state == ST_RUN && !ki->ki_tab.b_active) ki->ki_wticks = 0; else if (++ki->ki_wticks >= 30) { ki->ki_wticks = 0; printf("kdb%d: lost interrupt\n", i); /* kdbreset(ki); */ panic("kdb lost interrupt"); } } } /* * Do a panic dump. */ #define DBSIZE 32 /* dump 16K at a time */ struct kdbdumpspace { struct kdb1ca kd_ca; struct mscp kd_rsp; struct mscp kd_cmd; } kdbdumpspace; kdbdump(dev) dev_t dev; { register struct kdbdumpspace *kd; register struct kdb_regs *k; register int i; struct uba_device *ui; char *start; int num, blk, unit, maxsz, blkoff; /* * Make sure the device is a reasonable place on which to dump. */ unit = kdbunit(dev); if (unit >= NKRA) return (ENXIO); ui = PHYS(struct uba_device *, kdbdinfo[unit]); if (ui == NULL || ui->ui_alive == 0) return (ENXIO); /* * Find and initialise the KDB; get the physical address of the * device registers, and of communications area and command and * response packet. */ k = PHYS(struct kdbinfo *, &kdbinfo[ui->ui_ctlr])->ki_physkdb; kd = PHYS(struct kdbdumpspace *, &kdbdumpspace); /* * Initialise the controller, with one command and one response * packet. */ bi_reset(&k->kdb_bi); if (kdbdumpwait(k, KDB_STEP1)) return (EFAULT); k->kdb_sw = KDB_ERR; if (kdbdumpwait(k, KDB_STEP2)) return (EFAULT); k->kdb_sw = (int)&kd->kd_ca.ca_rspdsc; if (kdbdumpwait(k, KDB_STEP3)) return (EFAULT); k->kdb_sw = ((int)&kd->kd_ca.ca_rspdsc) >> 16; if (kdbdumpwait(k, KDB_STEP4)) return (EFAULT); k->kdb_sw = KDB_GO; /* * Set up the command and response descriptor, then set the * controller characteristics and bring the drive on line. * Note that all uninitialised locations in kd_cmd are zero. */ kd->kd_ca.ca_rspdsc = (long)&kd->kd_rsp.mscp_cmdref; kd->kd_ca.ca_cmddsc = (long)&kd->kd_cmd.mscp_cmdref; /* kd->kd_cmd.mscp_sccc.sccc_ctlrflags = 0; */ /* kd->kd_cmd.mscp_sccc.sccc_version = 0; */ if (kdbdumpcmd(M_OP_SETCTLRC, k, kd, ui->ui_ctlr)) return (EFAULT); kd->kd_cmd.mscp_unit = ui->ui_slave; if (kdbdumpcmd(M_OP_ONLINE, k, kd, ui->ui_ctlr)) return (EFAULT); /* * Pick up the drive type from the on line end packet; * convert that to a dump area size and a disk offset. * Note that the assembler uses pc-relative addressing * to get at kdbtypes[], no need for PHYS(). */ i = kd->kd_rsp.mscp_onle.onle_drivetype; if (i >= NTYPES || kdbtypes[i].ut_name == 0) { printf("disk type %d unknown\ndump "); return (EINVAL); } printf("on %s ", kdbtypes[i].ut_name); maxsz = kdbtypes[i].ut_sizes[kdbpart(dev)].nblocks; blkoff = kdbtypes[i].ut_sizes[kdbpart(dev)].blkoff; /* * Dump all of physical memory, or as much as will fit in the * space provided. */ start = 0; num = maxfree; if (dumplo < 0) return (EINVAL); if (dumplo + num >= maxsz) num = maxsz - dumplo; blkoff += dumplo; /* * Write out memory, DBSIZE pages at a time. * N.B.: this code depends on the fact that the sector * size == the page size. */ while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; kd->kd_cmd.mscp_unit = ui->ui_slave; kd->kd_cmd.mscp_seq.seq_lbn = btop(start) + blkoff; kd->kd_cmd.mscp_seq.seq_bytecount = blk << PGSHIFT; kd->kd_cmd.mscp_seq.seq_buffer = (long)start | KDB_PHYS; if (kdbdumpcmd(M_OP_WRITE, k, kd, ui->ui_ctlr)) return (EIO); start += blk << PGSHIFT; num -= blk; } return (0); /* made it! */ } /* * Wait for some of the bits in `bits' to come on. If the error bit * comes on, or ten seconds pass without response, return true (error). */ kdbdumpwait(k, bits) register struct kdb_regs *k; register int bits; { register int timo = todr() + 1000; while ((k->kdb_sa & bits) == 0) { if (k->kdb_sa & KDB_ERR) { printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits); return (1); } if (todr() >= timo) { printf("timeout\ndump "); return (1); } } return (0); } /* * Feed a command to the KDB50, wait for its response, and return * true iff something went wrong. */ kdbdumpcmd(op, k, kd, ctlr) int op; register struct kdb_regs *k; register struct kdbdumpspace *kd; int ctlr; { register int n; #define mp (&kd->kd_rsp) kd->kd_cmd.mscp_opcode = op; kd->kd_cmd.mscp_msglen = MSCP_MSGLEN; kd->kd_rsp.mscp_msglen = MSCP_MSGLEN; kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT; kd->kd_ca.ca_cmddsc |= MSCP_OWN | MSCP_INT; if (k->kdb_sa & KDB_ERR) { printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits); return (1); } n = k->kdb_ip; n = todr() + 1000; for (;;) { if (todr() > n) { printf("timeout\ndump "); return (1); } if (kd->kd_ca.ca_cmdint) kd->kd_ca.ca_cmdint = 0; if (kd->kd_ca.ca_rspint == 0) continue; kd->kd_ca.ca_rspint = 0; if (mp->mscp_opcode == (op | M_OP_END)) break; printf("\n"); switch (MSCP_MSGTYPE(mp->mscp_msgtc)) { case MSCPT_SEQ: printf("sequential"); break; case MSCPT_DATAGRAM: mscp_decodeerror("kdb", ctlr, mp); printf("datagram"); break; case MSCPT_CREDITS: printf("credits"); break; case MSCPT_MAINTENANCE: printf("maintenance"); break; default: printf("unknown (type 0x%x)", MSCP_MSGTYPE(mp->mscp_msgtc)); break; } printf(" ignored\ndump "); kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT; } if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("error: op 0x%x => 0x%x status 0x%x\ndump ", op, mp->mscp_opcode, mp->mscp_status); return (1); } return (0); #undef mp } /* * Return the size of a partition, if known, or -1 if not. */ kdbsize(dev) dev_t dev; { register int unit = kdbunit(dev); register struct uba_device *ui; register struct size *st; if (unit >= NKRA || (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0) return (-1); st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(dev)]; if (st->nblocks == -1) { int s = spl5(); /* * We need to have the drive on line to find the size * of this particular partition. * IS IT OKAY TO GO TO SLEEP IN THIS ROUTINE? * (If not, better not page on one of these...) */ if ((ui->ui_flags & UNIT_ONLINE) == 0) { if (kdb_bringonline(ui, 0)) { splx(s); return (-1); } } splx(s); if (st->blkoff > ra_dsize[unit]) return (-1); return (ra_dsize[unit] - st->blkoff); } return (st->nblocks); } #endif NKDB > 0