* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* @(#)kdb.c 7.10 (Berkeley) 12/16/90
* KDB50/MSCP device driver
* rethink BI software interface
* write bad block forwarding code
#include "kra.h" /* XXX */
#define DRIVENAMES "kra" /* XXX */
* 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 */
#define NRSP (1 << NRSPL2)
#define NCMD (1 << NCMDL2)
#include "../include/pte.h"
#include "../include/cpu.h"
#include "../vax/mscpvar.h"
#include "../include/mtpr.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.
/* 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
#define KI_MAPSIZ (NCMD + 2)
struct map
*ki_map
; /* resource map */
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 */
#define ki_ctlr ki_mi.mi_ctlr
#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 */
#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 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) */
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 */
15884, 0, /* A=blk 0 thru 15883 */
33440, 15884, /* B=blk 15884 thru 49323 */
-1, 0, /* C=blk 0 thru end */
82080, 49324, /* G=blk 49324 thru 131403 */
-1, 131404, /* H=blk 131404 thru end */
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 */
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
char *ut_name
; /* drive type name */
struct size
*ut_sizes
; /* partition tables */
"ra80", kra80_sizes
, /* 1 = ra80 */
"ra60", kra60_sizes
, /* 4 = ra60 */
"ra81", kra81_sizes
, /* 5 = ra81 */
* 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 */
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
,
* Miscellaneous private variables.
char kdbsr_bits
[] = KDBSR_BITS
;
struct uba_device
*kdbip
[NKDB
][MAXUNIT
];
/* inverting pointers: ctlr & unit => `Unibus'
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 */
* If kdbprobe is called, return 0 to keep Unibus code from attempting
* to use this device. XXX rethink
* Configure in a KDB50 controller.
kdbconfig(kdbnum
, va
, pa
, vec
)
register struct kdbinfo
*ki
;
extern int (*kdbint0
[])();
(*kdbint0
[0])(0); /* this is a config botch */
* Set up local KDB status.
ki
->ki_kdb
= (struct kdb_regs
*)va
;
ki
->ki_physkdb
= (struct kdb_regs
*)pa
;
(struct map
*)malloc((u_long
)(KI_MAPSIZ
* sizeof(struct map
)),
if (ki
->ki_map
== NULL
) {
printf("kdb%d: cannot get memory for ptes\n", kdbnum
);
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
;
* Note that by the time kdbslave is called, the interrupt vector
* for the KDB50 has been set up (so that kdbunconf() will be called).
register struct uba_device
*ui
;
register struct kdbinfo
*ki
;
register struct mscp
*mp
;
int next
= 0, type
, timeout
, tries
, i
;
* Make sure the controller is fully initialised, by waiting
ki
= &kdbinfo
[ui
->ui_ctlr
];
if (ki
->ki_state
== ST_RUN
)
timeout
= todr() + 1000; /* 10 seconds */
if (ki
->ki_state
== ST_RUN
) /* made it */
printf("kdb%d: controller hung\n", ki
->ki_ctlr
);
* 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'.
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_modifier
= M_GUM_NEXTUNIT
;
mp
->mscp_unit
= ui
->ui_slave
;
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
i
= ki
->ki_kdb
->kdb_ip
; /* initiate polling */
printf("kdb%d: no response to Get Unit Status request\n",
ki
->ki_flags
&= ~KDB_INSLAVE
;
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 */
* Figure out why it is off line. It may be because
* it is nonexistent, or because it is spun down, or
switch (mp
->mscp_status
& ~M_ST_MASK
) {
* No such drive, and there are none with
* higher unit numbers either, if we are
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.
* In service, or something else equally unusable.
printf("kdb%d: unit %d off line:", ki
->ki_ctlr
,
printf("kdb%d: unable to get unit status:", ki
->ki_ctlr
);
* 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
);
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);
* See if we already handle this drive.
* (Only likely if ui->ui_slave=='?'.)
if (kdbip
[ki
->ki_ctlr
][mp
->mscp_unit
] != NULL
)
* Make sure we know about this kind of drive.
* Others say we should treat unknowns as RA81s; I am
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
,
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
);
next
= mp
->mscp_unit
+ 1;
ui
->ui_flags
= 0; /* not on line, nor anything else */
ui
->ui_slave
= mp
->mscp_unit
;
* 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
register struct uba_device
*ui
;
timeout(kdbwatch
, (caddr_t
)0, hz
);
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.
register struct kdbinfo
*ki
;
register struct kdb_regs
*ka
= ki
->ki_kdb
;
* While we are thinking about it, reset the next command
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) */
while ((ka
->kdb_sa
& STEP0MASK
) == 0) {
printf("kdb%d: timeout during init\n", ki
->ki_ctlr
);
if ((ka
->kdb_sa
& STEP0MASK
) != KDB_STEP1
) {
printf("kdb%d: init failed, sa=%b\n", ki
->ki_ctlr
,
* Success! Record new state, and start step 1 initialisation.
* The rest is done in the interrupt handler.
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_
???;
ka
->kdb_bi
.bi_bcicsr
|= BCI_STOPEN
| BCI_IDENTEN
| BCI_UINTEN
|
/* 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
; /* ??? */
ka
->kdb_bi
.bi_uintrcsr
= ki
->ki_vec
;
ka
->kdb_sw
= KDB_ERR
| (NCMDL2
<< 11) | (NRSPL2
<< 8) | KDB_IE
|
register struct uba_device
*ui
;
register struct kdbinfo
*ki
;
* Make sure this is a reasonable open request.
if (unit
>= NKRA
|| (ui
= kdbdinfo
[unit
]) == 0 || ui
->ui_alive
== 0)
* Make sure the controller is running, by (re)initialising it if
ki
= &kdbinfo
[ui
->ui_ctlr
];
if (ki
->ki_state
!= ST_RUN
) {
if (ki
->ki_state
== ST_IDLE
&& kdbinit(ki
)) {
* 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
) {
printf("kdb%d: controller hung\n", ui
->ui_ctlr
);
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
if (kdb_bringonline(ui
, 0)) {
printf("%s%d: drive will not come on line\n",
kdbdriver
.ud_dname
, unit
);
* 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
;
register struct kdbinfo
*ki
= &kdbinfo
[ui
->ui_ctlr
];
register struct mscp
*mp
;
mp
= mscp_getcp(&ki
->ki_mi
, MSCP_DONTWAIT
);
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
;
while ((ui
->ui_flags
& UNIT_ONLINE
) == 0)
timeout(wakeup
, (caddr_t
)&ui
->ui_flags
, 10 * hz
);
sleep((caddr_t
)&ui
->ui_flags
, PRIBIO
);
if ((ui
->ui_flags
& UNIT_ONLINE
) == 0)
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
register struct uba_device
*ui
;
register struct size
*st
;
* Make sure this is a reasonable drive to use.
if ((unit
= kdbunit(bp
->b_dev
)) >= NKRA
||
(ui
= kdbdinfo
[unit
]) == NULL
|| ui
->ui_alive
== 0) {
* 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
;
* Work routine for kdbstrategy.
register int unit
= kdbunit(bp
->b_dev
);
register struct kdbinfo
*ki
;
* 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.)
ki
= &kdbinfo
[ui
->ui_ctlr
];
if (dp
->b_active
== 0 && (ui
->ui_flags
& UNIT_REQUEUE
) == 0) {
APPEND(dp
, &ki
->ki_tab
, b_forw
);
* Start activity on the controller.
* 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.
kdbmap(ki
, bp
, mapbase
, offset
, info
)
register struct pte
*spte
, *dpte
;
register struct proc
*rp
;
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
);
*mapbase
= PHYS(long, spte
);
if (bp
->b_flags
& B_PAGET
) {
spte
= &Usrptmap
[btokmx((struct pte
*)bp
->b_un
.b_addr
)];
if (spte
->pg_v
== 0) panic("kdbmap");
*mapbase
= PHYS(long, spte
);
/* 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
)
npf
= btoc(bp
->b_bcount
+ o
);
* 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....
/* CONSIDER CHANGING VM TO VALIDATE PAGES EARLIER */
for (dpte
= spte
, i
= npf
; --i
>= 0; dpte
++)
* Check for discontiguous physical pte addresses. It is
* not necessary to check each pte, since they come in clumps
i
= howmany(npf
+ (((int)spte
& PGOFSET
) / sizeof (*spte
)), NPTEPG
);
/* often i==1, and we can avoid work */
if ((++dpte
)->pg_pfnum
!= ++a
)
*mapbase
= kvtophys(spte
);
kdbstats
.ks_inval
++; /* temp */
if ((a
= rmalloc(ki
->ki_map
, (long)i
)) == 0) {
/* if offset > PGOFSET, btop(offset) indexes mapbase */
*mapbase
= ki
->ki_ptephys
;
*offset
= (a
<< PGSHIFT
) | o
;
*(int *)dpte
++ = PG_V
| *(int *)spte
++;
#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().
register struct kdbinfo
*ki
;
register struct buf
*bp
, *dp
;
register struct mscp
*mp
;
register struct uba_device
*ui
;
* 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
);
/* if insufficient credit, avoid overhead */
if (ki
->ki_mi
.mi_credits
<= MSCP_MINCREDITS
)
* 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
)
if ((bp
= dp
->b_actf
) == NULL
) {
ki
->ki_tab
.b_actf
= dp
->b_forw
;
if (ki
->ki_kdb
->kdb_sa
& KDB_ERR
) { /* ctlr fatal error */
/* 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_flags
|= KDB_GRIPED
;/* complain only once */
* 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
;
if ((ui
->ui_flags
& UNIT_HAVESTATUS
) == 0) {
mp
->mscp_opcode
= M_OP_GETUNITST
;
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.
ki
->ki_tab
.b_actf
= dp
->b_forw
;
ui
->ui_flags
|= UNIT_REQUEUE
;
mp
->mscp_unit
= ui
->ui_slave
;
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
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
;
dk_busy
|= 1 << 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
mscp_go(&ki
->ki_mi
, mp
, info
);
ncmd
++; /* note the transfer */
ki
->ki_tab
.b_active
++; /* another one going */
if (ncmd
) /* start some transfers */
ncmd
= ki
->ki_kdb
->kdb_ip
;
register struct kdbinfo
*ki
= &kdbinfo
[mi
->mi_ctlr
];
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.
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
);
* Interrupt routine. Depending on the state of the controller,
* continue initialisation, or acknowledge command and response
* interrupts, and process responses.
register struct kdbinfo
*ki
= &kdbinfo
[ctlr
];
register struct kdb_regs
*kdbaddr
= ki
->ki_kdb
;
register struct mscp
*mp
;
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
* Ignore unsolicited interrupts.
log(LOG_WARNING
, "kdb%d: stray intr\n", ctlr
);
* Begin step two initialisation.
if ((kdbaddr
->kdb_sa
& STEP1MASK
) != STEP1GOOD
) {
printf("kdb%d: init step %d failed, sa=%b\n",
ctlr
, i
, kdbaddr
->kdb_sa
, kdbsr_bits
);
if (ki
->ki_flags
& KDB_DOWAKE
) {
ki
->ki_flags
&= ~KDB_DOWAKE
;
wakeup((caddr_t
)&ki
->ki_flags
);
kdbaddr
->kdb_sw
= PHYS(int, &ki
->ki_ca
.ca_rspdsc
[0]);
* Begin step 3 initialisation.
if ((kdbaddr
->kdb_sa
& STEP2MASK
) != STEP2GOOD
) {
kdbaddr
->kdb_sw
= PHYS(int, &ki
->ki_ca
.ca_rspdsc
[0]) >> 16;
* Set controller characteristics (finish initialisation).
if ((kdbaddr
->kdb_sa
& STEP3MASK
) != STEP3GOOD
) {
i
= kdbaddr
->kdb_sa
& 0xff;
printf("kdb%d: version %d model %d\n",
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
ki
->ki_mi
.mi_credits
= MSCP_MINCREDITS
+ 1;
mp
= mscp_getcp(&ki
->ki_mi
, MSCP_DONTWAIT
);
if (mp
== NULL
) /* `cannot happen' */
ki
->ki_mi
.mi_credits
= 0;
mp
->mscp_opcode
= M_OP_SETCTLRC
;
mp
->mscp_sccc
.sccc_ctlrflags
= M_CF_ATTN
| M_CF_MISC
|
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
ki
->ki_state
= ST_SETCHAR
;
* Handle Set Ctlr Characteristics responses and operational
* responses (via mscp_dorsp).
log(LOG_ERR
, "kdb%d: driver bug, state %d\n", ctlr
,
if (kdbaddr
->kdb_sa
& KDB_ERR
) {/* ctlr fatal error */
* Handle buffer purge requests.
printf("kdb%d: purge bdp %d\n", ctlr
, ki
->ki_ca
.ca_bdp
);
* Check for response and command ring transitions.
if (ki
->ki_ca
.ca_rspint
) {
if (ki
->ki_ca
.ca_cmdint
) {
if (ki
->ki_tab
.b_actf
!= NULL
)
* Handle an error datagram. All we do now is decode it.
mscp_decodeerror(mi
->mi_md
->md_mname
, mi
->mi_ctlr
, mp
);
* The Set Controller Characteristics command finished.
* Record the new state of the controller.
register struct kdbinfo
*ki
= &kdbinfo
[mi
->mi_ctlr
];
if ((mp
->mscp_status
& M_ST_MASK
) == M_ST_SUCCESS
)
printf("kdb%d: SETCTLRC failed, status 0x%x\n",
ki
->ki_ctlr
, mp
->mscp_status
);
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
register struct mscp
*mp
;
* If it is a slave response, copy it to kdbslavereply for
if (mp
->mscp_opcode
== (M_OP_GETUNITST
| M_OP_END
) &&
(kdbinfo
[mi
->mi_ctlr
].ki_flags
& KDB_INSLAVE
) != 0) {
* Otherwise, it had better be an available attention response.
if (mp
->mscp_opcode
!= M_OP_AVAILATTN
)
/* 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.
register struct uba_device
*ui
;
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
);
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
);
* 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
);
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
]);
* We got some (configured) unit's status. Return DONE if it succeeded.
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
);
/* need to record later for bad block forwarding - for now, print */
%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
);
* A transfer failed. We get a chance to fix or restart it.
* Need to write the bad block forwaring code first....
register struct uba_device
*ui
;
register struct mscp
*mp
;
if (mp
->mscp_flags
& M_EF_BBLKR
) {
* A bad block report. Eventually we will
* restart this transfer, but for now, just
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" : "");
* 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
);
kdbioctl(dev
, cmd
, flag
, data
)
register int unit
= kdbunit(dev
);
if (unit
>= NKRA
|| uddinfo
[unit
] == NULL
)
* Initiate bad block replacement for the given LBN.
* (Should we allow modifiers?)
* Return the microcode revision for the KDB50 running
*(int *)data
= kdbinfo
[kdbdinfo
[unit
]->ui_ctlr
].ki_micro
;
* Return the size (in 512 byte blocks) of this
*(daddr_t
*)data
= ra_dsize
[unit
];
* Reset a KDB50 (self test and all).
register struct kdbinfo
*ki
;
printf("reset kdb%d", ki
->ki_ctlr
);
bi_selftest(&ki
->ki_kdb
.kdb_bi
);
rminit(ki
->ki_map
, (long)KI_PTES
, (long)1, "kdb", KI_MAPSIZ
);
mscp_requeue(&ki
->ki_mi
);
* Watchdog timer: If the controller is active, and no interrupts
* have occurred for 30 seconds, assume it has gone away.
register struct kdbinfo
*ki
;
timeout(kdbwatch
, (caddr_t
)0, hz
); /* every second */
for (i
= 0, ki
= kdbinfo
; i
< NKDB
; i
++, ki
++) {
if ((ki
->ki_flags
& KDB_ALIVE
) == 0)
if (ki
->ki_state
== ST_IDLE
)
if (ki
->ki_state
== ST_RUN
&& !ki
->ki_tab
.b_active
)
else if (++ki
->ki_wticks
>= 30) {
printf("kdb%d: lost interrupt\n", i
);
panic("kdb lost interrupt");
#define DBSIZE 32 /* dump 16K at a time */
register struct kdbdumpspace
*kd
;
register struct kdb_regs
*k
;
int num
, blk
, unit
, maxsz
, blkoff
;
* Make sure the device is a reasonable place on which to dump.
ui
= PHYS(struct uba_device
*, kdbdinfo
[unit
]);
if (ui
== NULL
|| ui
->ui_alive
== 0)
* Find and initialise the KDB; get the physical address of the
* device registers, and of communications area and command and
k
= PHYS(struct kdbinfo
*, &kdbinfo
[ui
->ui_ctlr
])->ki_physkdb
;
kd
= PHYS(struct kdbdumpspace
*, &kdbdumpspace
);
* Initialise the controller, with one command and one response
if (kdbdumpwait(k
, KDB_STEP1
))
if (kdbdumpwait(k
, KDB_STEP2
))
k
->kdb_sw
= (int)&kd
->kd_ca
.ca_rspdsc
;
if (kdbdumpwait(k
, KDB_STEP3
))
k
->kdb_sw
= ((int)&kd
->kd_ca
.ca_rspdsc
) >> 16;
if (kdbdumpwait(k
, KDB_STEP4
))
* 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
))
kd
->kd_cmd
.mscp_unit
= ui
->ui_slave
;
if (kdbdumpcmd(M_OP_ONLINE
, k
, kd
, ui
->ui_ctlr
))
* 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 ");
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
if (dumplo
+ num
>= maxsz
)
* Write out memory, DBSIZE pages at a time.
* N.B.: this code depends on the fact that the sector
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 (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).
register struct kdb_regs
*k
;
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
);
printf("timeout\ndump ");
* Feed a command to the KDB50, wait for its response, and return
* true iff something went wrong.
kdbdumpcmd(op
, k
, kd
, ctlr
)
register struct kdb_regs
*k
;
register struct kdbdumpspace
*kd
;
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
);
printf("timeout\ndump ");
if (kd
->kd_ca
.ca_rspint
== 0)
if (mp
->mscp_opcode
== (op
| M_OP_END
))
switch (MSCP_MSGTYPE(mp
->mscp_msgtc
)) {
mscp_decodeerror("kdb", ctlr
, mp
);
printf("unknown (type 0x%x)",
MSCP_MSGTYPE(mp
->mscp_msgtc
));
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 the size of a partition, if known, or -1 if not.
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)
st
= &kdbtypes
[ui
->ui_type
].ut_sizes
[kdbpart(dev
)];
* 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)) {
if (st
->blkoff
> ra_dsize
[unit
])
return (ra_dsize
[unit
] - st
->blkoff
);