summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1998-05-06 22:14:48 +0000
committerjulian <julian@FreeBSD.org>1998-05-06 22:14:48 +0000
commit0cb054bfeab729f000a87716a669b995215502fc (patch)
treef0dd71a43184ebf7ebaf3423df86fdafb6633e4b /sys/i386
parent719d62b3b0b317b7bd93f23baf86382fc6c6969f (diff)
downloadFreeBSD-src-0cb054bfeab729f000a87716a669b995215502fc.zip
FreeBSD-src-0cb054bfeab729f000a87716a669b995215502fc.tar.gz
Add dump support to the DEVFS/slice code.
now we can actually catch our crashes :-) Submitted by: Luoqi Chen <luoqi@chen.ml.org> (the man who's everywhere)
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/autoconf.c7
-rw-r--r--sys/i386/isa/fd.c6
-rw-r--r--sys/i386/isa/wd.c161
3 files changed, 166 insertions, 8 deletions
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
index ff061a6..90bee3c 100644
--- a/sys/i386/i386/autoconf.c
+++ b/sys/i386/i386/autoconf.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
- * $Id: autoconf.c,v 1.94 1998/04/20 03:57:23 julian Exp $
+ * $Id: autoconf.c,v 1.95 1998/04/20 21:53:07 julian Exp $
*/
/*
@@ -398,6 +398,7 @@ setdumpdev(dev)
{
int maj, psize;
long newdumplo;
+ struct partinfo pi;
if (dev == NODEV) {
dumpdev = dev;
@@ -418,7 +419,9 @@ setdumpdev(dev)
* and nuke dodump sysctl (too many knobs), and move this to
* kern_shutdown.c...
*/
- if (dkpart(dev) != SWAP_PART)
+ if (bdevsw[maj]->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, 0, NULL) != 0)
+ return (ENODEV);
+ if (pi.part->p_fstype != FS_SWAP)
return (ENODEV);
newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
if (newdumplo < 0)
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
index 2d74c99..9afadd2 100644
--- a/sys/i386/isa/fd.c
+++ b/sys/i386/isa/fd.c
@@ -43,7 +43,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.109 1998/04/19 23:31:41 julian Exp $
+ * $Id: fd.c,v 1.110 1998/04/22 10:25:15 julian Exp $
*
*/
@@ -2196,9 +2196,9 @@ fdsopen(void *private, int flags, int mode, struct proc *p)
sd = private;
if((flags & (FREAD|FWRITE)) != 0) {
- return(Fdopen(makedev(0,sd->minor), 0 , 0, p));
+ return(Fdopen(makedev(0,sd->minor), flags , mode, p));
} else {
- return(fdclose(makedev(0,sd->minor), 0 , 0, p));
+ return(fdclose(makedev(0,sd->minor), 0 , mode, p));
}
}
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index 6dafca1..06ac100 100644
--- a/sys/i386/isa/wd.c
+++ b/sys/i386/isa/wd.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
- * $Id: wd.c,v 1.163 1998/04/24 07:54:00 julian Exp $
+ * $Id: wd.c,v 1.164 1998/05/05 14:27:26 sos Exp $
*/
/* TODO:
@@ -263,6 +263,7 @@ static sl_h_IO_req_t wdsIOreq; /* IO req downward (to device) */
static sl_h_ioctl_t wdsioctl; /* ioctl req downward (to device) */
static sl_h_open_t wdsopen; /* downwards travelling open */
/*static sl_h_close_t wdsclose; */ /* downwards travelling close */
+static sl_h_dump_t wdsdump; /* core dump req downward */
static void wds_init(void*);
static struct slice_handler slicetype = {
@@ -278,7 +279,8 @@ static struct slice_handler slicetype = {
NULL, /* revoke */
NULL, /* claim */
NULL, /* verify */
- NULL /* upconfig */
+ NULL, /* upconfig */
+ &wdsdump
};
#endif
@@ -970,7 +972,7 @@ wdstart(int ctrlr)
blknum - ds_offset) + ds_offset;
}
#else
- if (du->dk_flags & DKFL_SINGLE) {
+ if (du->dk_flags & DKFL_SINGLE && du->slice->handler_up) {
(void) (*du->slice->handler_up->upconf)(du->slice,
SLCIOCTRANSBAD, (caddr_t)&blknum, 0, 0);
}
@@ -2782,5 +2784,158 @@ wdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p)
}
}
+static int
+wdsdump(void *private, int32_t start, int32_t num)
+{
+ register struct disk *du;
+ long blknum, blkchk, blkcnt, blknext;
+ long cylin, head, sector;
+ long secpertrk, secpercyl, nblocks;
+ char *addr;
+
+ du = private;
+ if (du->dk_state < OPEN)
+ return (ENXIO);
+
+ secpertrk = du->dk_dd.d_nsectors;
+ secpercyl = du->dk_dd.d_secpercyl;
+
+ /* Recalibrate the drive. */
+ DELAY(5); /* ATA spec XXX NOT */
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
+ || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
+ || wdsetctlr(du) != 0) {
+ wderror((struct buf *)NULL, du, "wddump: recalibrate failed");
+ return (EIO);
+ }
+
+ du->dk_flags |= DKFL_SINGLE;
+ addr = (char *) 0;
+ blknum = start;
+ while (num > 0) {
+ blkcnt = num;
+ if (blkcnt > MAXTRANSFER)
+ blkcnt = MAXTRANSFER;
+ /* Keep transfer within current cylinder. */
+ if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
+ blkcnt = secpercyl - (blknum % secpercyl);
+ blknext = blknum + blkcnt;
+
+ /*
+ * See if one of the sectors is in the bad sector list
+ * (if we have one). If the first sector is bad, then
+ * reduce the transfer to this one bad sector; if another
+ * sector is bad, then reduce reduce the transfer to
+ * avoid any bad sectors.
+ */
+ if (du->dk_flags & DKFL_SINGLE && du->slice->handler_up) {
+ for (blkchk = blknum; blkchk < blknum + blkcnt; blkchk++) {
+ daddr_t blknew = blkchk;
+ (void) (*du->slice->handler_up->upconf)(du->slice,
+ SLCIOCTRANSBAD, (caddr_t)&blknew, 0, 0);
+ if (blknew != blkchk) {
+ /* Found bad block. */
+ blkcnt = blkchk - blknum;
+ if (blkcnt > 0) {
+ blknext = blknum + blkcnt;
+ goto out;
+ }
+ blkcnt = 1;
+ blknext = blknum + blkcnt;
+#if 1 || defined(WDDEBUG)
+ printf("bad block %lu -> %lu\n",
+ blknum, blknew);
+#endif
+ break;
+ }
+ }
+ }
+out:
+
+ /* Compute disk address. */
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+
+#if 0
+ /* Let's just talk about this first... */
+ pg("cylin l%d head %ld sector %ld addr 0x%x count %ld",
+ cylin, head, sector, addr, blkcnt);
+#endif
+
+ /* Do the write. */
+ if (wdcommand(du, cylin, head, sector, blkcnt, WDCC_WRITE)
+ != 0) {
+ wderror((struct buf *)NULL, du,
+ "wdsdump: timeout waiting to to give command");
+ return (EIO);
+ }
+ while (blkcnt != 0) {
+ if (is_physical_memory((vm_offset_t)addr))
+ pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
+ trunc_page(addr), VM_PROT_READ, TRUE);
+ else
+ pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
+ trunc_page(0), VM_PROT_READ, TRUE);
+
+ /* Ready to send data? */
+ DELAY(5); /* ATA spec */
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT)
+ < 0) {
+ wderror((struct buf *)NULL, du,
+ "wdsdump: timeout waiting for DRQ");
+ return (EIO);
+ }
+ if (du->dk_flags & DKFL_32BIT)
+ outsl(du->dk_port + wd_data,
+ CADDR1 + ((int)addr & PAGE_MASK),
+ DEV_BSIZE / sizeof(long));
+ else
+ outsw(du->dk_port + wd_data,
+ CADDR1 + ((int)addr & PAGE_MASK),
+ DEV_BSIZE / sizeof(short));
+ addr += DEV_BSIZE;
+ /*
+ * If we are dumping core, it may take a while.
+ * So reassure the user and hold off any watchdogs.
+ */
+ if ((unsigned)addr % (1024 * 1024) == 0) {
+#ifdef HW_WDOG
+ if (wdog_tickler)
+ (*wdog_tickler)();
+#endif /* HW_WDOG */
+ printf("%ld ", num / (1024 * 1024 / DEV_BSIZE));
+ }
+ num--;
+ blkcnt--;
+ }
+
+ /* Wait for completion. */
+ DELAY(5); /* ATA spec XXX NOT */
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) < 0) {
+ wderror((struct buf *)NULL, du,
+ "wdsdump: timeout waiting for status");
+ return (EIO);
+ }
+
+ /* Check final status. */
+ if (du->dk_status
+ & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ | WDCS_ERR)
+ != (WDCS_READY | WDCS_SEEKCMPLT)) {
+ wderror((struct buf *)NULL, du,
+ "wdsdump: extra DRQ, or error");
+ return (EIO);
+ }
+
+ /* Update block count. */
+ blknum = blknext;
+
+ /* Operator aborting dump? */
+ if (cncheckc() != -1)
+ return (EINTR);
+ }
+ return (0);
+}
+
#endif /* SLICE */
#endif /* NWDC > 0 */
OpenPOWER on IntegriCloud